Skip to contentSkip to conversation

nilfs-utils: skip inefficient gc operations

PATCH Superseded Andreas Rohner 5 participants 44 messages Jan 21, 2014 – Jan 26, 2014 29 messages not in the archive

Subsystems (2)

v2 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

v2 cover nilfs-utils: skip inefficient gc operations

Hi,

This is the second version of this patch set. It replaces the kind of hacky use of v_flags with a proper implementation of NILFS_IOCTL_SET_SUINFO ioctl.

v1->v2
* Implementation of NILFS_IOCTL_SET_SUINFO
* Added mc_min_free_blocks_threshold config option (if clean segments < min_clean_segments)
* Added new command line param for nilfs-clean
* Update man- and config-files
* Simpler benchmark

This patch set implements a small new feature and there shouldn't be any compatibility issues. It enables the GC to check how much free space can be gained from cleaning a segment and if it is less than a certain threshold it will abort the operation and try a different segment. Although no blocks need to be moved, the SUFILE entry of the corresponding segment needs to be updated to avoid an infinite loop.

This is potentially useful for all gc policies, but it is especially beneficial for the timestamp policy. Lets assume for example a NILFS2 volume with 20% static files and lets assume these static files are in the oldest segments. The current timestamp policy will select the oldest segments and, since the data is static, move them mostly unchanged to new segments. After a while they will become the oldest segments again. Then timestamp will move them again. These moving operations are expensive and unnecessary.

I used a simple benchmark to test the patch set (only a few lines of C). I used a 100 GB partition and performed the following steps:

1. Write a 20 GB file
2. Write a 50 GB file
3. Overwrite chunks of 1 MB within the 50 GB file at random
4. Repeat step 3 until 60 GB of data is written

Steps 3 and 4 are only perfomed to get the GC started. So the benchmark writes a 130 GB in total to a 100 GB partition.

HHD:

    Timestamp GB Written: 340.7574
    Timestamp GB Read:    208.2935
    Timestamp Runtime:    7787.546s

    Patched GB Written:   313.2566
    Patched GB Read:      182.6389
    Patched Runtime:      7410.892s

SSD:

    Timestamp GB Written: 679.3901
    Timestamp GB Read:    242.59
    Timestamp Runtime:    3022.081s

    Patched GB Written:   500.0095
    Patched GB Read:      157.475   
    Patched Runtime:      2313.448

The results for the HDD clearly show, that about 20 GB less data has been written and read in the patched version. It is reasonable to assume, that these 20 GB are the static data.

The speed of the GC was tuned to the HDD. It was probably too aggressive for the much faster SSD. That is probably the reason why the difference in GB written and read is much higher than 20 GB.

Best regards,
Andreas Rohner
---
Andreas Rohner (5):
nilfs-utils: cldconfig add an option to set minimal free blocks
nilfs-utils: cleanerd: add custom error value to enable fast retry
nilfs-utils: refactoring of nilfs_reclaim_segment to add minblocks
param
nilfs-utils: add support for NILFS_IOCTL_SET_SUINFO ioctl
nilfs-utils: man: add description of min_free_blocks_threshold

 include/nilfs.h                   |  2 ++
 include/nilfs2_fs.h               | 41 ++++++++++++++++++++++++++++++++
 include/nilfs_cleaner.h           | 19 ++++++++-------
 include/nilfs_gc.h                |  6 +++--
 lib/gc.c                          | 49 ++++++++++++++++++++++++++++++++++++---
 lib/nilfs.c                       | 26 +++++++++++++++++++++
 man/nilfs-clean.8                 |  4 ++++
 man/nilfs_cleanerd.conf.5         |  9 +++++++
 sbin/cleanerd/cldconfig.c         | 40 ++++++++++++++++++++++++++++++++
 sbin/cleanerd/cldconfig.h         |  4 ++++
 sbin/cleanerd/cleanerd.c          | 38 +++++++++++++++++++++++++++---
 sbin/cleanerd/nilfs_cleanerd.conf |  9 +++++++
 sbin/nilfs-clean/nilfs-clean.c    | 18 ++++++++++----
 sbin/nilfs-resize/nilfs-resize.c  |  2 +-
 14 files changed, 245 insertions(+), 22 deletions(-)
Signature · 6 lines
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): [email protected]

#2 lore raw

PATCH v2 1/5 nilfs-utils: cldconfig add an option to set minimal free blocks

With this option the user can specify the minimal number of free/dead blocks before a segment can be cleaned. This is a threshold for the GC to prevent needless moving of data. If there are less free blocks to gain from cleaning a segment than the specified number, the GC will abort and try again with a different segment.

By setting it to 0 this feature is effectively disabled.

---
 include/nilfs_cleaner.h           | 19 ++++++++++---------
 sbin/cleanerd/cldconfig.c         | 40 +++++++++++++++++++++++++++++++++++++++
 sbin/cleanerd/cldconfig.h         |  4 ++++
 sbin/cleanerd/cleanerd.c          | 23 ++++++++++++++++++++++
 sbin/cleanerd/nilfs_cleanerd.conf |  9 +++++++++
 sbin/nilfs-clean/nilfs-clean.c    | 18 ++++++++++++++----
 6 files changed, 100 insertions(+), 13 deletions(-)
include/nilfs_cleaner.h +10 -9
index 0bf02aa..42c4aa7 100644
@@ -46,17 +46,18 @@ struct nilfs_cleaner_args {
 	uint64_t start_segnum;	/* start segment number */
 	uint64_t nsegs;		/* number of segments */
 	uint32_t runtime; /* runtime in seconds */
-	uint32_t pad2;
+	uint32_t min_free_blocks_threshold;
 };
 /* valid flags */
-#define NILFS_CLEANER_ARG_PROTECTION_PERIOD	(1 << 0)
-#define NILFS_CLEANER_ARG_NSEGMENTS_PER_CLEAN	(1 << 1)
-#define NILFS_CLEANER_ARG_CLEANING_INTERVAL	(1 << 2)
-#define NILFS_CLEANER_ARG_USAGE_RATE_THRESHOLD	(1 << 3) /* reserved */
-#define NILFS_CLEANER_ARG_START_SEGNUM		(1 << 4) /* reserved */
-#define NILFS_CLEANER_ARG_NSEGS			(1 << 5) /* reserved */
-#define NILFS_CLEANER_ARG_NPASSES		(1 << 6) /* reserved */
-#define NILFS_CLEANER_ARG_RUNTIME		(1 << 7) /* reserved */
+#define NILFS_CLEANER_ARG_PROTECTION_PERIOD		(1 << 0)
+#define NILFS_CLEANER_ARG_NSEGMENTS_PER_CLEAN		(1 << 1)
+#define NILFS_CLEANER_ARG_CLEANING_INTERVAL		(1 << 2)
+#define NILFS_CLEANER_ARG_USAGE_RATE_THRESHOLD		(1 << 3) /* reserved */
+#define NILFS_CLEANER_ARG_START_SEGNUM			(1 << 4) /* reserved */
+#define NILFS_CLEANER_ARG_NSEGS				(1 << 5) /* reserved */
+#define NILFS_CLEANER_ARG_NPASSES			(1 << 6) /* reserved */
+#define NILFS_CLEANER_ARG_RUNTIME			(1 << 7) /* reserved */
+#define NILFS_CLEANER_ARG_MIN_FREE_BLOCKS_THRESHOLD	(1 << 8)
 
 enum {
 	NILFS_CLEANER_STATUS_IDLE,
sbin/cleanerd/cldconfig.c +40 -0
index 270d360..4d7589c 100644
@@ -456,6 +456,34 @@ nilfs_cldconfig_handle_mc_nsegments_per_clean(struct nilfs_cldconfig *config,
 }
 
 static int
+nilfs_cldconfig_handle_min_free_blocks(struct nilfs_cldconfig *config,
+				       char **tokens, size_t ntoks,
+				       struct nilfs *nilfs)
+{
+	unsigned long n;
+
+	if (nilfs_cldconfig_get_ulong_argument(tokens, ntoks, &n) < 0)
+		return 0;
+
+	config->cf_min_free_blocks_threshold = n;
+	return 0;
+}
+
+static int
+nilfs_cldconfig_handle_mc_min_free_blocks(struct nilfs_cldconfig *config,
+					  char **tokens, size_t ntoks,
+					  struct nilfs *nilfs)
+{
+	unsigned long n;
+
+	if (nilfs_cldconfig_get_ulong_argument(tokens, ntoks, &n) < 0)
+		return 0;
+
+	config->cf_mc_min_free_blocks_threshold = n;
+	return 0;
+}
+
+static int
 nilfs_cldconfig_handle_cleaning_interval(struct nilfs_cldconfig *config,
 					 char **tokens, size_t ntoks,
 					 struct nilfs *nilfs)
@@ -576,6 +604,14 @@ nilfs_cldconfig_keyword_table[] = {
 		"log_priority", 2, 2,
 		nilfs_cldconfig_handle_log_priority
 	},
+	{
+		"min_free_blocks_threshold", 2, 2,
+		nilfs_cldconfig_handle_min_free_blocks
+	},
+	{
+		"mc_min_free_blocks_threshold", 2, 2,
+		nilfs_cldconfig_handle_mc_min_free_blocks
+	},
 };
 
 #define NILFS_CLDCONFIG_NKEYWORDS			\
@@ -641,6 +677,10 @@ static void nilfs_cldconfig_set_default(struct nilfs_cldconfig *config,
 	config->cf_retry_interval.tv_usec = 0;
 	config->cf_use_mmap = NILFS_CLDCONFIG_USE_MMAP;
 	config->cf_log_priority = NILFS_CLDCONFIG_LOG_PRIORITY;
+	config->cf_min_free_blocks_threshold =
+		NILFS_CLDCONFIG_MIN_FREE_BLOCKS_THRESHOLD;
+	config->cf_mc_min_free_blocks_threshold =
+		NILFS_CLDCONFIG_MC_MIN_FREE_BLOCKS_THRESHOLD;
 }
 
 static inline int iseol(int c)
sbin/cleanerd/cldconfig.h +4 -0
index 188ce9b..49ee6be 100644
@@ -102,6 +102,8 @@ struct nilfs_cldconfig {
 	struct timeval cf_retry_interval;
 	int cf_use_mmap;
 	int cf_log_priority;
+	unsigned long cf_min_free_blocks_threshold;
+	unsigned long cf_mc_min_free_blocks_threshold;
 };
 
 #define NILFS_CLDCONFIG_SELECTION_POLICY_IMPORTANCE	\
@@ -120,6 +122,8 @@ struct nilfs_cldconfig {
 #define NILFS_CLDCONFIG_RETRY_INTERVAL			60
 #define NILFS_CLDCONFIG_USE_MMAP			1
 #define NILFS_CLDCONFIG_LOG_PRIORITY			LOG_INFO
+#define NILFS_CLDCONFIG_MIN_FREE_BLOCKS_THRESHOLD	256
+#define NILFS_CLDCONFIG_MC_MIN_FREE_BLOCKS_THRESHOLD	128
 
 #define NILFS_CLDCONFIG_NSEGMENTS_PER_CLEAN_MAX	32
 
sbin/cleanerd/cleanerd.c +23 -0
index 86dfcf7..eb6eace 100644
@@ -172,6 +172,7 @@ struct nilfs_cleanerd {
 	struct timeval cleaning_interval;
 	struct timeval target;
 	struct timeval timeout;
+	unsigned long min_free_blocks_threshold;
 	__u64 prev_nongc_ctime;
 	mqd_t recvq;
 	char *recvq_name;
@@ -184,6 +185,7 @@ struct nilfs_cleanerd {
 	long mm_ncleansegs;
 	struct timeval mm_protection_period;
 	struct timeval mm_cleaning_interval;
+	unsigned long mm_min_free_blocks_threshold;
 };
 
 /**
@@ -459,6 +461,14 @@ nilfs_cleanerd_protection_period(struct nilfs_cleanerd *cleanerd)
 		&cleanerd->config.cf_protection_period;
 }
 
+static unsigned long
+nilfs_cleanerd_min_free_blocks_threshold(struct nilfs_cleanerd *cleanerd)
+{
+	return cleanerd->running == 2 ?
+		cleanerd->mm_min_free_blocks_threshold :
+		cleanerd->min_free_blocks_threshold;
+}
+
 static void
 nilfs_cleanerd_reduce_ncleansegs_for_retry(struct nilfs_cleanerd *cleanerd)
 {
@@ -998,6 +1008,13 @@ static int nilfs_cleanerd_cmd_run(struct nilfs_cleanerd *cleanerd,
 		cleanerd->mm_cleaning_interval =
 			cleanerd->cleaning_interval;
 	}
+	/* minimal free blocks threshold */
+	if (req2->args.valid & NILFS_CLEANER_ARG_MIN_FREE_BLOCKS_THRESHOLD) {
+		cleanerd->mm_min_free_blocks_threshold =
+			req2->args.min_free_blocks_threshold;
+	} else {
+		cleanerd->mm_min_free_blocks_threshold = 0;
+	}
 	/* number of passes */
 	if (req2->args.valid & NILFS_CLEANER_ARG_NPASSES) {
 		if (!req2->args.npasses)
@@ -1235,10 +1252,14 @@ static int nilfs_cleanerd_handle_clean_check(struct nilfs_cleanerd *cleanerd,
 		/* disk space is close to limit -- accelerate cleaning */
 		cleanerd->ncleansegs = config->cf_mc_nsegments_per_clean;
 		cleanerd->cleaning_interval = config->cf_mc_cleaning_interval;
+		cleanerd->min_free_blocks_threshold =
+				config->cf_mc_min_free_blocks_threshold;
 	} else {
 		/* continue to run */
 		cleanerd->ncleansegs = config->cf_nsegments_per_clean;
 		cleanerd->cleaning_interval = config->cf_cleaning_interval;
+		cleanerd->min_free_blocks_threshold =
+				config->cf_min_free_blocks_threshold;
 	}
 
 	return 0; /* do gc */
@@ -1424,6 +1445,8 @@ static int nilfs_cleanerd_clean_loop(struct nilfs_cleanerd *cleanerd)
 
 	cleanerd->ncleansegs = cleanerd->config.cf_nsegments_per_clean;
 	cleanerd->cleaning_interval = cleanerd->config.cf_cleaning_interval;
+	cleanerd->min_free_blocks_threshold =
+			cleanerd->config.cf_min_free_blocks_threshold;
 
 
 	if (nilfs_cleanerd_automatic_suspend(cleanerd))
sbin/cleanerd/nilfs_cleanerd.conf +9 -0
index 26872aa..23ef8de 100644
@@ -51,6 +51,15 @@ mc_cleaning_interval	1
 # Retry interval in seconds.
 retry_interval		60
 
+# Minimal number of free blocks before a segment
+# can be cleaned. Set to 0 to disable it.
+min_free_blocks_threshold	256
+
+# Minimal number of free blocks before a segment
+# can be cleaned. Set to 0 to disable it.
+# if clean segments < min_clean_segments
+mc_min_free_blocks_threshold	128
+
 # Use mmap when reading segments if supported.
 use_mmap
 
sbin/nilfs-clean/nilfs-clean.c +14 -4
index 55abd55..23b7e61 100644
@@ -77,6 +77,7 @@ const static struct option long_option[] = {
 	{"stop", no_argument, NULL, 'b'},
 	{"suspend", no_argument, NULL, 's'},
 	{"speed", required_argument, NULL, 'S'},
+	{"free-blocks-threshold", optional_argument, NULL, 't'},
 	{"verbose", no_argument, NULL, 'v'},
 	{"version", no_argument, NULL, 'V'},
 	{NULL, 0, NULL, 0}
@@ -95,12 +96,15 @@ const static struct option long_option[] = {
 	"  -s, --suspend\t\tsuspend cleaner\n"				\
 	"  -S, --speed=COUNT[/SECONDS]\n"				\
 	"               \t\tset GC speed\n"				\
+	"  -t, --free-blocks-threshold=COUNT\n"				\
+	"               \t\tset minimal number of free blocks before\n"	\
+	"               \t\ta segment can be cleaned\n"			\
 	"  -v, --verbose\t\tverbose mode\n"				\
 	"  -V, --version\t\tdisplay version and exit\n"
 #else
 #define NILFS_CLEAN_USAGE						\
 	"Usage: %s [-b] [-c [conffile]] [-h] [-l] [-p protection-period]" \
-	"          [-q] [-r] [-s] [-S gc-speed] [-v] [-V] [device]\n"
+	"          [-q] [-r] [-s] [-S gc-speed] [-t blocks][-v] [-V] [device]\n"
 #endif	/* _GNU_SOURCE */
 
 
@@ -124,6 +128,7 @@ static const char *conffile = NULL;
 static unsigned long protection_period = ULONG_MAX;
 static int nsegments_per_clean = 2;
 static struct timespec cleaning_interval = { 0, 100000000 };   /* 100 msec */
+static unsigned long min_free_blocks_threshold;
 
 static sigjmp_buf nilfs_clean_env;
 static struct nilfs_cleaner *nilfs_cleaner;
@@ -164,9 +169,11 @@ static int nilfs_clean_do_run(struct nilfs_cleaner *cleaner)
 	args.nsegments_per_clean = nsegments_per_clean;
 	args.cleaning_interval = cleaning_interval.tv_sec;
 	args.cleaning_interval_nsec = cleaning_interval.tv_nsec;
+	args.min_free_blocks_threshold = min_free_blocks_threshold;
 	args.valid = (NILFS_CLEANER_ARG_NPASSES |
 		      NILFS_CLEANER_ARG_CLEANING_INTERVAL |
-		      NILFS_CLEANER_ARG_NSEGMENTS_PER_CLEAN);
+		      NILFS_CLEANER_ARG_NSEGMENTS_PER_CLEAN |
+		      NILFS_CLEANER_ARG_MIN_FREE_BLOCKS_THRESHOLD);
 
 	if (protection_period != ULONG_MAX) {
 		args.protection_period = protection_period;
@@ -434,10 +441,10 @@ static void nilfs_clean_parse_options(int argc, char *argv[])
 	int c;
 
 #ifdef _GNU_SOURCE
-	while ((c = getopt_long(argc, argv, "bc::hlp:qrsS:vV",
+	while ((c = getopt_long(argc, argv, "bc::hlp:qrsS:t:vV",
 				long_option, &option_index)) >= 0) {
 #else
-	while ((c = getopt(argc, argv, "bc::hlp:qrsS:vV")) >= 0) {
+	while ((c = getopt(argc, argv, "bc::hlp:qrsS:t:vV")) >= 0) {
 #endif	/* _GNU_SOURCE */
 		switch (c) {
 		case 'b':
@@ -472,6 +479,9 @@ static void nilfs_clean_parse_options(int argc, char *argv[])
 			if (nilfs_clean_parse_gcspeed(optarg) < 0)
 				exit(EXIT_FAILURE);
 			break;
+		case 't':
+			min_free_blocks_threshold = strtoul(optarg, NULL, 10);
+			break;
 		case 'v':
 			verbose = 1;
 			break;
Signature · 6 lines
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 22b5b3ac403052d3044dc8c1bebe323191376c03.1390310509.git.andreas.rohner-hi6Y0CQ0nG0@public.gmane.org

#4 lore raw

Re: [PATCH v2 1/5] nilfs-utils: cldconfig add an option to set minimal free blocks

Hi Andreas,

I like the idea you're introducing; should lessen trashing by GC on my workstations.

Quoted 5 lines · On Tuesday 21 of January 2014 14:59:40 you wrote:

With this option the user can specify the minimal number of free/dead blocks before a segment can be cleaned. This is a threshold for the GC to prevent needless moving of data. If there are less free blocks to gain from cleaning a segment than the specified number, the GC will abort and try again with a different segment.

Will your patches be smart enough to re-claim space if the only available free blocks are under threshold?

Scenario: FS is running out of free space, and the free blocks to be reclaimed are scattered through segments in small numbers. Several segments have a small number of free blocks, but in each segment the amount is under the threshold.

Regards,

Signature · 8 lines
dexen deVries

[[[↓][→]]]

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#5 lore raw

Re: [PATCH v2 1/5] nilfs-utils: cldconfig add an option to set minimal free blocks

Hi Dexen,

Quoted 7 lines · dexen deVries

Will your patches be smart enough to re-claim space if the only available free blocks are under threshold?

Scenario: FS is running out of free space, and the free blocks to be reclaimed are scattered through segments in small numbers. Several segments have a small number of free blocks, but in each segment the amount is under the threshold.

No my patches won't do that, but there are two new config options. Namely min_free_blocks_threshold and mc_min_free_blocks_threshold, whereby the latter is used if the number of clean segments is below min_clean_segments, similar to the other mc options.

To accommodate your scenario you could simple set a very low value or even 0 to mc_min_free_blocks_threshold. So if the number of clean segments drops below min_clean_segments my patches would be disabled.

Regards,
Andreas Rohner
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#6 lore raw

Re: [PATCH v2 1/5] nilfs-utils: cldconfig add an option to set minimal free blocks

In reply to a message not in the archive
Quoted 5 lines · Andreas Rohner

With this option the user can specify the minimal number of free/dead blocks before a segment can be cleaned. This is a threshold for the GC to prevent needless moving of data. If there are less free blocks to gain from cleaning a segment than the specified number, the GC will abort and try again with a different segment.

Come to think of it, "blocks" is not a good unit. Maybe I should change that to "% of a segment" and/or "KB/MB". It shouldn't be hard...

Regards,
Andreas Rohner

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#7 lore raw

Re: [PATCH v2 1/5] nilfs-utils: cldconfig add an option to set minimal free blocks

In reply to a message not in the archive
Quoted 2 lines · Andreas Rohner

With this option the user can specify the minimal number of free/dead blocks before a segment can be cleaned.

"Free or dead" or "free and dead"? What do you mean by free blocks? "Free blocks" sounds for me as blocks that I can allocate and to use immediately without any operations. If you mean invalid blocks (blocks that it was updated in this segment) then I need to do garbage collection operation for making it free. So, free blocks are really confusing term. And "dead blocks" sounds for me not very good.

Quoted 36 lines

This is a threshold for the GC
to prevent needless moving of data. If there are less free blocks to gain from cleaning a segment than the specified number, the GC will abort and try again with a different segment.

By setting it to 0 this feature is effectively disabled.

---

include/nilfs_cleaner.h           | 19 ++++++++++---------
sbin/cleanerd/cldconfig.c         | 40 +++++++++++++++++++++++++++++++++++++++
sbin/cleanerd/cldconfig.h         |  4 ++++
sbin/cleanerd/cleanerd.c          | 23 ++++++++++++++++++++++
sbin/cleanerd/nilfs_cleanerd.conf |  9 +++++++++
sbin/nilfs-clean/nilfs-clean.c    | 18 ++++++++++++++----
6 files changed, 100 insertions(+), 13 deletions(-)
include/nilfs_cleaner.h +1 -8
index 0bf02aa..42c4aa7 100644
@@ -46,17 +46,18 @@ struct nilfs_cleaner_args {
 	uint64_t start_segnum;	/* start segment number */
 	uint64_t nsegs;		/* number of segments */
 	uint32_t runtime; /* runtime in seconds */
-	uint32_t pad2;
+	uint32_t min_free_blocks_threshold;
 };
 /* valid flags */
-#define NILFS_CLEANER_ARG_PROTECTION_PERIOD	(1 << 0)
-#define NILFS_CLEANER_ARG_NSEGMENTS_PER_CLEAN	(1 << 1)
-#define NILFS_CLEANER_ARG_CLEANING_INTERVAL	(1 << 2)
-#define NILFS_CLEANER_ARG_USAGE_RATE_THRESHOLD	(1 << 3) /* reserved */
-#define NILFS_CLEANER_ARG_START_SEGNUM		(1 << 4) /* reserved */
-#define NILFS_CLEANER_ARG_NSEGS			(1 << 5) /* reserved */
-#define NILFS_CLEANER_ARG_NPASSES		(1 << 6) /* reserved */

include/nilfs_cleaner.h struct nilfs_cleaner_args { · line 60

Quoted 10 lines
include/nilfs_cleaner.h +9 -1
-#define NILFS_CLEANER_ARG_RUNTIME		(1 << 7) /* reserved */
+#define NILFS_CLEANER_ARG_PROTECTION_PERIOD		(1 << 0)
+#define NILFS_CLEANER_ARG_NSEGMENTS_PER_CLEAN		(1 << 1)
+#define NILFS_CLEANER_ARG_CLEANING_INTERVAL		(1 << 2)
+#define NILFS_CLEANER_ARG_USAGE_RATE_THRESHOLD		(1 << 3) /* reserved */
+#define NILFS_CLEANER_ARG_START_SEGNUM			(1 << 4) /* reserved */
+#define NILFS_CLEANER_ARG_NSEGS				(1 << 5) /* reserved */
+#define NILFS_CLEANER_ARG_NPASSES			(1 << 6) /* reserved */
+#define NILFS_CLEANER_ARG_RUNTIME			(1 << 7) /* reserved */
+#define NILFS_CLEANER_ARG_MIN_FREE_BLOCKS_THRESHOLD	(1 << 8)

What about NILFS_CLEANER_ARG_MIN_FBLK_THRESHOLD?
But free blocks really confuse me.

Quoted 82 lines
include/nilfs_cleaner.h +0 -0
 enum {
 	NILFS_CLEANER_STATUS_IDLE,
sbin/cleanerd/cldconfig.c +0 -0
index 270d360..4d7589c 100644
@@ -456,6 +456,34 @@ nilfs_cldconfig_handle_mc_nsegments_per_clean(struct nilfs_cldconfig *config,
 }
 

static int

sbin/cleanerd/cldconfig.c +28 -0
+nilfs_cldconfig_handle_min_free_blocks(struct nilfs_cldconfig *config,
+				       char **tokens, size_t ntoks,
+				       struct nilfs *nilfs)
+{
+	unsigned long n;
+
+	if (nilfs_cldconfig_get_ulong_argument(tokens, ntoks, &n) < 0)
+		return 0;
+
+	config->cf_min_free_blocks_threshold = n;
+	return 0;
+}
+
+static int
+nilfs_cldconfig_handle_mc_min_free_blocks(struct nilfs_cldconfig *config,
+					  char **tokens, size_t ntoks,
+					  struct nilfs *nilfs)
+{
+	unsigned long n;
+
+	if (nilfs_cldconfig_get_ulong_argument(tokens, ntoks, &n) < 0)
+		return 0;
+
+	config->cf_mc_min_free_blocks_threshold = n;
+	return 0;
+}
+
+static int

nilfs_cldconfig_handle_cleaning_interval(struct nilfs_cldconfig *config,
char **tokens, size_t ntoks, struct nilfs *nilfs)

sbin/cleanerd/cldconfig.c +12 -0
@@ -576,6 +604,14 @@ nilfs_cldconfig_keyword_table[] = {
 		"log_priority", 2, 2,
 		nilfs_cldconfig_handle_log_priority
 	},
+	{
+		"min_free_blocks_threshold", 2, 2,
+		nilfs_cldconfig_handle_min_free_blocks
+	},
+	{
+		"mc_min_free_blocks_threshold", 2, 2,
+		nilfs_cldconfig_handle_mc_min_free_blocks
+	},
 };
 
 #define NILFS_CLDCONFIG_NKEYWORDS			\
@@ -641,6 +677,10 @@ static void nilfs_cldconfig_set_default(struct nilfs_cldconfig *config,
 	config->cf_retry_interval.tv_usec = 0;
 	config->cf_use_mmap = NILFS_CLDCONFIG_USE_MMAP;
 	config->cf_log_priority = NILFS_CLDCONFIG_LOG_PRIORITY;
+	config->cf_min_free_blocks_threshold =
+		NILFS_CLDCONFIG_MIN_FREE_BLOCKS_THRESHOLD;
+	config->cf_mc_min_free_blocks_threshold =
+		NILFS_CLDCONFIG_MC_MIN_FREE_BLOCKS_THRESHOLD;
 }
 
 static inline int iseol(int c)
sbin/cleanerd/cldconfig.h +2 -0
index 188ce9b..49ee6be 100644
@@ -102,6 +102,8 @@ struct nilfs_cldconfig {
 	struct timeval cf_retry_interval;
 	int cf_use_mmap;
 	int cf_log_priority;
+	unsigned long cf_min_free_blocks_threshold;
+	unsigned long cf_mc_min_free_blocks_threshold;
 };
 
 #define NILFS_CLDCONFIG_SELECTION_POLICY_IMPORTANCE	\

sbin/cleanerd/cldconfig.h struct nilfs_cldconfig { · line 126

Quoted 5 lines
sbin/cleanerd/cldconfig.h +2 -0
@@ -120,6 +122,8 @@ struct nilfs_cldconfig {
 #define NILFS_CLDCONFIG_RETRY_INTERVAL			60
 #define NILFS_CLDCONFIG_USE_MMAP			1
 #define NILFS_CLDCONFIG_LOG_PRIORITY			LOG_INFO
+#define NILFS_CLDCONFIG_MIN_FREE_BLOCKS_THRESHOLD	256
+#define NILFS_CLDCONFIG_MC_MIN_FREE_BLOCKS_THRESHOLD	128

Why 256 or 128? What is good? What is bad?
I am a user. How can I define what value is appropriate?
How should I think for choosing some value?
For example, I want to have the fastest performance as possible. How can I define an appropriate value? Or, maybe, I want to clean as many segments as possible. How should I think?

Or, maybe, I want combination of GC policies.

Thanks,
Vyacheslav Dubeyko.

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): B1FCAEBD-EB58-4A06-BD6B-7D4FB533D9F1-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org

#9 lore raw

Re: [PATCH v2 1/5] nilfs-utils: cldconfig add an option to set minimal free blocks

Quoted 6 lines · Vyacheslav Dubeyko
Quoted 2 lines · Andreas Rohner

With this option the user can specify the minimal number of free/dead blocks before a segment can be cleaned.

Quoted 6 lines

"Free or dead" or "free and dead"? What do you mean by free blocks? "Free blocks" sounds for me as blocks that I can allocate and to use immediately without any operations. If you mean invalid blocks (blocks that it was updated in this segment) then I need to do garbage collection operation for making it free. So, free blocks are really confusing term. And "dead blocks" sounds for me not very good.

I mean updated or deleted blocks, that need to be garbage collected. Here [1] they are called "dead blocks".

Quoted 41 lines
Quoted 41 lines

This is a threshold for the GC
to prevent needless moving of data. If there are less free blocks to gain from cleaning a segment than the specified number, the GC will abort and try again with a different segment.

By setting it to 0 this feature is effectively disabled.

---

include/nilfs_cleaner.h           | 19 ++++++++++---------
sbin/cleanerd/cldconfig.c         | 40 +++++++++++++++++++++++++++++++++++++++
sbin/cleanerd/cldconfig.h         |  4 ++++
sbin/cleanerd/cleanerd.c          | 23 ++++++++++++++++++++++
sbin/cleanerd/nilfs_cleanerd.conf |  9 +++++++++
sbin/nilfs-clean/nilfs-clean.c    | 18 ++++++++++++++----
6 files changed, 100 insertions(+), 13 deletions(-)
include/nilfs_cleaner.h +5 -9
index 0bf02aa..42c4aa7 100644
@@ -46,17 +46,18 @@ struct nilfs_cleaner_args {
 	uint64_t start_segnum;	/* start segment number */
 	uint64_t nsegs;		/* number of segments */
 	uint32_t runtime; /* runtime in seconds */
-	uint32_t pad2;
+	uint32_t min_free_blocks_threshold;
 };
 /* valid flags */
-#define NILFS_CLEANER_ARG_PROTECTION_PERIOD	(1 << 0)
-#define NILFS_CLEANER_ARG_NSEGMENTS_PER_CLEAN	(1 << 1)
-#define NILFS_CLEANER_ARG_CLEANING_INTERVAL	(1 << 2)
-#define NILFS_CLEANER_ARG_USAGE_RATE_THRESHOLD	(1 << 3) /* reserved */
-#define NILFS_CLEANER_ARG_START_SEGNUM		(1 << 4) /* reserved */
-#define NILFS_CLEANER_ARG_NSEGS			(1 << 5) /* reserved */
-#define NILFS_CLEANER_ARG_NPASSES		(1 << 6) /* reserved */
-#define NILFS_CLEANER_ARG_RUNTIME		(1 << 7) /* reserved */
+#define NILFS_CLEANER_ARG_PROTECTION_PERIOD		(1 << 0)
+#define NILFS_CLEANER_ARG_NSEGMENTS_PER_CLEAN		(1 << 1)
+#define NILFS_CLEANER_ARG_CLEANING_INTERVAL		(1 << 2)
+#define NILFS_CLEANER_ARG_USAGE_RATE_THRESHOLD		(1 << 3) /* reserved */
Quoted 8 lines

include/nilfs_cleaner.h struct nilfs_cleaner_args { · line 60

Quoted 5 lines
include/nilfs_cleaner.h +5 -0
+#define NILFS_CLEANER_ARG_START_SEGNUM			(1 << 4) /* reserved */
+#define NILFS_CLEANER_ARG_NSEGS				(1 << 5) /* reserved */
+#define NILFS_CLEANER_ARG_NPASSES			(1 << 6) /* reserved */
+#define NILFS_CLEANER_ARG_RUNTIME			(1 << 7) /* reserved */
+#define NILFS_CLEANER_ARG_MIN_FREE_BLOCKS_THRESHOLD	(1 << 8)

What about NILFS_CLEANER_ARG_MIN_FBLK_THRESHOLD?
But free blocks really confuse me.

Yes maybe the name is a bit confusing.

Quoted 15 lines

include/nilfs_cleaner.h struct nilfs_cldconfig { · line 126

Quoted 7 lines
include/nilfs_cleaner.h +2 -0
 #define NILFS_CLDCONFIG_SELECTION_POLICY_IMPORTANCE	\
@@ -120,6 +122,8 @@ struct nilfs_cldconfig {
 #define NILFS_CLDCONFIG_RETRY_INTERVAL			60
 #define NILFS_CLDCONFIG_USE_MMAP			1
 #define NILFS_CLDCONFIG_LOG_PRIORITY			LOG_INFO
+#define NILFS_CLDCONFIG_MIN_FREE_BLOCKS_THRESHOLD	256
+#define NILFS_CLDCONFIG_MC_MIN_FREE_BLOCKS_THRESHOLD	128

Why 256 or 128? What is good? What is bad?
I am a user. How can I define what value is appropriate?
How should I think for choosing some value?
For example, I want to have the fastest performance as possible. How can I define an appropriate value? Or, maybe, I want to clean as many segments as possible. How should I think?

Quoted 1 line

Or, maybe, I want combination of GC policies.

It is the minimal number of dead or free or invalid or however you want to call them blocks, before a segment is allowed to be cleaned by the GC. It is a tradeoff, but you are right it is not very intuitive. As I stated before I am going to change that in the next version.

br,
Andreas Rohner

[1] http://lwn.net/Articles/522507/
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#10 lore raw

PATCH v2 2/5 nilfs-utils: cleanerd: add custom error value to enable fast retry

In reply to a message not in the archive

This patch adds the custom error value EGCTRYAGAIN, which signals to cleanerd to retry the GC process as soon as possible with no timeout.

If the GC decides not to do any real work and only changes a few metadata bytes, there is no need for a timeout. Furthermore if the GC is running, there is probably not enough free space on the device and it is crucial to retry quickly.

---
 include/nilfs_gc.h       |  2 ++
 sbin/cleanerd/cleanerd.c | 10 +++++++++-
 2 files changed, 11 insertions(+), 1 deletion(-)
include/nilfs_gc.h +2 -0
index 72e9947..7628ce1 100644
@@ -27,4 +27,6 @@ static inline int nilfs_suinfo_reclaimable(const struct nilfs_suinfo *si)
 
 extern void (*nilfs_gc_logger)(int priority, const char *fmt, ...);
 
+#define EGCTRYAGAIN 513
+
 #endif /* NILFS_GC_H */
sbin/cleanerd/cleanerd.c +9 -1
index eb6eace..575656b 100644
@@ -167,6 +167,7 @@ struct nilfs_cleanerd {
 	int running;
 	int fallback;
 	int retry_cleaning;
+	int no_timeout;
 	int shutdown;
 	long ncleansegs;
 	struct timeval cleaning_interval;
@@ -883,7 +884,7 @@ static int nilfs_cleanerd_recalc_interval(struct nilfs_cleanerd *cleanerd,
 	interval = nilfs_cleanerd_cleaning_interval(cleanerd);
 	/* timercmp() does not work for '>=' or '<='. */
 	/* curr >= target */
-	if (!timercmp(&curr, &cleanerd->target, <)) {
+	if (!timercmp(&curr, &cleanerd->target, <) || cleanerd->no_timeout) {
 		cleanerd->timeout.tv_sec = 0;
 		cleanerd->timeout.tv_usec = 0;
 		timeradd(&curr, interval, &cleanerd->target);
@@ -1369,6 +1370,7 @@ static ssize_t nilfs_cleanerd_clean_segments(struct nilfs_cleanerd *cleanerd,
 		       "number: %m");
 		goto out;
 	}
+	cleanerd->no_timeout = 0;
 
 	ret = nilfs_reclaim_segment(cleanerd->nilfs, segnums, nsegs,
 				    protseq, protcno);
@@ -1394,6 +1396,11 @@ static ssize_t nilfs_cleanerd_clean_segments(struct nilfs_cleanerd *cleanerd,
 			cleanerd->retry_cleaning = 0;
 		}
 
+	} else if (ret == -EGCTRYAGAIN) {
+		cleanerd->fallback = 0;
+		cleanerd->retry_cleaning = 1;
+		cleanerd->no_timeout = 1;
+		ret = 0;
 	} else if (ret < 0 && errno == ENOMEM) {
 		nilfs_cleanerd_reduce_ncleansegs_for_retry(cleanerd);
 		cleanerd->fallback = 1;
@@ -1436,6 +1443,7 @@ static int nilfs_cleanerd_clean_loop(struct nilfs_cleanerd *cleanerd)
 	cleanerd->running = 1;
 	cleanerd->fallback = 0;
 	cleanerd->retry_cleaning = 0;
+	cleanerd->no_timeout = 0;
 	nilfs_cnoconv_reset(cleanerd->cnoconv);
 	nilfs_gc_logger = syslog;
 
Signature · 6 lines
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): e9d3dd17318a994fe7e2c100368212e0b4029e13.1390310509.git.andreas.rohner-hi6Y0CQ0nG0@public.gmane.org

#12 lore raw

Re: [PATCH v2 2/5] nilfs-utils: cleanerd: add custom error value to enable fast retry

Quoted 8 lines · Andreas Rohner

This patch adds the custom error value EGCTRYAGAIN, which signals to cleanerd to retry the GC process as soon as possible with no timeout.

If the GC decides not to do any real work and only changes a few metadata bytes, there is no need for a timeout. Furthermore if the GC is running, there is probably not enough free space on the device and it is crucial to retry quickly.

What does it defend us from eating 100% of CPU?

Quoted 11 lines

---
include/nilfs_gc.h | 2 ++
sbin/cleanerd/cleanerd.c | 10 +++++++++-

2 files changed, 11 insertions(+), 1 deletion(-)
include/nilfs_gc.h +0 -0
index 72e9947..7628ce1 100644

include/nilfs_gc.h static inline int nilfs_suinfo_reclaimable(const struct nilfs_suinfo *si) · line 30

Quoted 4 lines
include/nilfs_gc.h +1 -0
@@ -27,4 +27,6 @@ static inline int nilfs_suinfo_reclaimable(const struct nilfs_suinfo *si)
 
 extern void (*nilfs_gc_logger)(int priority, const char *fmt, ...);
 
+#define EGCTRYAGAIN 513

Why do you declare a new constant? What does it means value of 513? What bad in EAGAIN?

Thanks,
Vyacheslav Dubeyko.

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): FE7FB751-68F4-48C3-A97A-782F4F6E69FE-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org

#14 lore raw

Re: [PATCH v2 2/5] nilfs-utils: cleanerd: add custom error value to enable fast retry

Quoted 6 lines · Vyacheslav Dubeyko
Quoted 3 lines · Andreas Rohner

This patch adds the custom error value EGCTRYAGAIN, which signals to cleanerd to retry the GC process as soon as possible with no timeout.

Quoted 7 lines
Quoted 5 lines

If the GC decides not to do any real work and only changes a few metadata bytes, there is no need for a timeout. Furthermore if the GC is running, there is probably not enough free space on the device and it is crucial to retry quickly.

What does it defend us from eating 100% of CPU?

Nothing really, but I don't think it's a big problem, because there is no possibility that you have constant 100% CPU. For every segment the timestamp is updated, so it will be protected by the protection period for a while. But you could be right. Maybe it is better to use a smaller timout instead of no timeout. I think I will change that in the next version of my patch.

Quoted 12 lines
Quoted 12 lines

---
include/nilfs_gc.h | 2 ++
sbin/cleanerd/cleanerd.c | 10 +++++++++-

2 files changed, 11 insertions(+), 1 deletion(-)
include/nilfs_gc.h +0 -0
index 72e9947..7628ce1 100644
@@ -27,4 +27,6 @@ static inline int nilfs_suinfo_reclaimable(const struct nilfs_suinfo *si)
 
Quoted 6 lines

include/nilfs_gc.h static inline int nilfs_suinfo_reclaimable(const struct nilfs_suinfo *si) · line 30

Quoted 3 lines
include/nilfs_gc.h +1 -0
 extern void (*nilfs_gc_logger)(int priority, const char *fmt, ...);
 
+#define EGCTRYAGAIN 513

Why do you declare a new constant? What does it means value of 513? What bad in EAGAIN?

I just thought that it's not a good idea to use an error code, that really could be returned from some system call. 513 is just 512+1. I wanted to make sure, that my error code does not conflict with any other existing errors < 512.

Come to think of it, maybe you are right. I don't think that any of the calls in nilfs_reclaim_segment would return EAGAIN. So we could use it theoretically. But if a real error occurred, that returned EAGAIN for some reason, we could end up with very undesirable results.

br,
Andreas Rohner

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#15 lore raw

PATCH v2 3/5 nilfs-utils: refactoring of nilfs_reclaim_segment to add minblocks param

In reply to a message not in the archive

nilfs_reclaim_segment gathers all the necessary information to decide, how many reclaimable blocks there are in the segments that are to be cleaned.

By enabling the passing of the threshold value
minblocks, nilfs_reclaim_segment can check the actual value against the threshold.

---
 include/nilfs_gc.h               | 4 ++--
 lib/gc.c                         | 5 +++--
 sbin/cleanerd/cleanerd.c         | 5 +++--
 sbin/nilfs-resize/nilfs-resize.c | 2 +-
 4 files changed, 9 insertions(+), 7 deletions(-)
include/nilfs_gc.h +2 -2
index 7628ce1..f9fbde4 100644
@@ -15,8 +15,8 @@
 #include "nilfs.h"
 
 ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
-			      __u64 *segnums, size_t nsegs,
-			      __u64 protseq, nilfs_cno_t protcno);
+			      __u64 *segnums, size_t nsegs, __u64 protseq,
+			      nilfs_cno_t protcno, unsigned long minblocks);
 
 
 static inline int nilfs_suinfo_reclaimable(const struct nilfs_suinfo *si)
lib/gc.c +3 -2
index 1152299..0b0e2d6 100644
@@ -607,10 +607,11 @@ static int nilfs_toss_bdescs(struct nilfs_vector *bdescv)
  * @nsegs: size of the @segnums array
  * @protseq: start of sequence number of protected segments
  * @protcno: start checkpoint number of protected period
+ * @minblocks: minimal number of free blocks in a segment
  */
 ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
-			      __u64 *segnums, size_t nsegs,
-			      __u64 protseq, nilfs_cno_t protcno)
+			      __u64 *segnums, size_t nsegs, __u64 protseq,
+			      nilfs_cno_t protcno, unsigned long minblocks)
 {
 	struct nilfs_vector *vdescv, *bdescv, *periodv, *vblocknrv;
 	sigset_t sigset, oldset, waitset;
sbin/cleanerd/cleanerd.c +3 -2
index 575656b..6dd9d24 100644
@@ -1372,8 +1372,9 @@ static ssize_t nilfs_cleanerd_clean_segments(struct nilfs_cleanerd *cleanerd,
 	}
 	cleanerd->no_timeout = 0;
 
-	ret = nilfs_reclaim_segment(cleanerd->nilfs, segnums, nsegs,
-				    protseq, protcno);
+	ret = nilfs_reclaim_segment(cleanerd->nilfs, segnums,
+			nsegs, protseq, protcno,
+			nilfs_cleanerd_min_free_blocks_threshold(cleanerd));
 	if (ret > 0) {
 		for (i = 0; i < ret; i++)
 			syslog(LOG_DEBUG, "segment %llu cleaned",
sbin/nilfs-resize/nilfs-resize.c +1 -1
index c8b0868..2850268 100644
@@ -595,7 +595,7 @@ static ssize_t nilfs_resize_move_segments(struct nilfs *nilfs,
 			return -1;
 
 		ret = nilfs_reclaim_segment(nilfs, snp, nc,
-					    sustat.ss_prot_seq, 0);
+					    sustat.ss_prot_seq, 0, 0);
 		if (ret < 0)
 			return -1;
 
Signature · 6 lines
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 36ef66ee15b3de8ca00815a6baa7bf6b62ca57d4.1390310509.git.andreas.rohner-hi6Y0CQ0nG0@public.gmane.org

#17 lore raw

Re: [PATCH v2 3/5] nilfs-utils: refactoring of nilfs_reclaim_segment to add minblocks param

Quoted 21 lines · Andreas Rohner

nilfs_reclaim_segment gathers all the necessary information to decide, how many reclaimable blocks there are in the segments that are to be cleaned.

By enabling the passing of the threshold value
minblocks, nilfs_reclaim_segment can check the actual value against the threshold.

---
 include/nilfs_gc.h               | 4 ++--
 lib/gc.c                         | 5 +++--
 sbin/cleanerd/cleanerd.c         | 5 +++--
 sbin/nilfs-resize/nilfs-resize.c | 2 +-
 4 files changed, 9 insertions(+), 7 deletions(-)
include/nilfs_gc.h +0 -0
index 7628ce1..f9fbde4 100644

include/nilfs_gc.h line 19

Quoted 7 lines
include/nilfs_gc.h +2 -2
@@ -15,8 +15,8 @@
 #include "nilfs.h"
 
 ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
-			      __u64 *segnums, size_t nsegs,
-			      __u64 protseq, nilfs_cno_t protcno);
+			      __u64 *segnums, size_t nsegs, __u64 protseq,
+			      nilfs_cno_t protcno, unsigned long minblocks);

This breaks compatibility of libnilfsgc library.

Please add new function with the extended arguments, the old function can share implementation of the new function.

Ryusuke Konishi

Quoted 55 lines
include/nilfs_gc.h +0 -0
 static inline int nilfs_suinfo_reclaimable(const struct nilfs_suinfo *si)
lib/gc.c +3 -2
index 1152299..0b0e2d6 100644
@@ -607,10 +607,11 @@ static int nilfs_toss_bdescs(struct nilfs_vector *bdescv)
  * @nsegs: size of the @segnums array
  * @protseq: start of sequence number of protected segments
  * @protcno: start checkpoint number of protected period
+ * @minblocks: minimal number of free blocks in a segment
  */
 ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
-			      __u64 *segnums, size_t nsegs,
-			      __u64 protseq, nilfs_cno_t protcno)
+			      __u64 *segnums, size_t nsegs, __u64 protseq,
+			      nilfs_cno_t protcno, unsigned long minblocks)
 {
 	struct nilfs_vector *vdescv, *bdescv, *periodv, *vblocknrv;
 	sigset_t sigset, oldset, waitset;
sbin/cleanerd/cleanerd.c +3 -2
index 575656b..6dd9d24 100644
@@ -1372,8 +1372,9 @@ static ssize_t nilfs_cleanerd_clean_segments(struct nilfs_cleanerd *cleanerd,
 	}
 	cleanerd->no_timeout = 0;
 
-	ret = nilfs_reclaim_segment(cleanerd->nilfs, segnums, nsegs,
-				    protseq, protcno);
+	ret = nilfs_reclaim_segment(cleanerd->nilfs, segnums,
+			nsegs, protseq, protcno,
+			nilfs_cleanerd_min_free_blocks_threshold(cleanerd));
 	if (ret > 0) {
 		for (i = 0; i < ret; i++)
 			syslog(LOG_DEBUG, "segment %llu cleaned",
sbin/nilfs-resize/nilfs-resize.c +1 -1
index c8b0868..2850268 100644
@@ -595,7 +595,7 @@ static ssize_t nilfs_resize_move_segments(struct nilfs *nilfs,
 			return -1;
 
 		ret = nilfs_reclaim_segment(nilfs, snp, nc,
-					    sustat.ss_prot_seq, 0);
+					    sustat.ss_prot_seq, 0, 0);
 		if (ret < 0)
 			return -1;
 
Signature · 6 lines
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#18 lore raw

PATCH v2 4/5 nilfs-utils: add support for NILFS_IOCTL_SET_SUINFO ioctl

In reply to a message not in the archive

With this ioctl the segment usage information in the SUFILE can be updated from userspace.

This is useful, because it allows the GC to modify and update segment usage entries for specific segments, which enables it to avoid unnecessary write operations.

If a segment needs to be cleaned, but there is no or very little free space to be gained, the cleaning operation basically degrades to needless expensive copying of data. In the end the only thing that changes is the location of the data and a timestamp in the segment usage info. With this ioctl the GC can skip the copying and update the segment usage entries directly instead.

Additionally this patch implements a simple check in nilfs_reclaim_segment. If the number of free blocks that can be gained by cleaning the segments is below the threshold of minblocks, it simply updates the segment usage information instead.

---
 include/nilfs.h     |  2 ++
 include/nilfs2_fs.h | 41 +++++++++++++++++++++++++++++++++++++++++
 lib/gc.c            | 44 +++++++++++++++++++++++++++++++++++++++++++-
 lib/nilfs.c         | 26 ++++++++++++++++++++++++++
 4 files changed, 112 insertions(+), 1 deletion(-)
include/nilfs.h +2 -0
index 56286a9..1e9b034 100644
@@ -299,6 +299,8 @@ int nilfs_delete_checkpoint(struct nilfs *, nilfs_cno_t);
 int nilfs_get_cpstat(const struct nilfs *, struct nilfs_cpstat *);
 ssize_t nilfs_get_suinfo(const struct nilfs *, __u64, struct nilfs_suinfo *,
 			 size_t);
+ssize_t nilfs_set_suinfo(const struct nilfs *, struct nilfs_suinfo_update *,
+			 size_t);
 int nilfs_get_sustat(const struct nilfs *, struct nilfs_sustat *);
 ssize_t nilfs_get_vinfo(const struct nilfs *, struct nilfs_vinfo *, size_t);
 ssize_t nilfs_get_bdescs(const struct nilfs *, struct nilfs_bdesc *, size_t);
include/nilfs2_fs.h +41 -0

52 lines not on this page · raw message

lib/gc.c +43 -1

62 lines not on this page · raw message

lib/nilfs.c +26 -0
index 7265830..dbd03e6 100644
@@ -548,6 +548,32 @@ ssize_t nilfs_get_suinfo(const struct nilfs *nilfs, __u64 segnum,
 }
 
 /**
+ * nilfs_set_suinfo -
+ * @nilfs:
+ * @sup: an array of nilfs_suinfo_update structs
+ * @nsup: number of elements in sup
+ */
+ssize_t nilfs_set_suinfo(const struct nilfs *nilfs,
+			 struct nilfs_suinfo_update *sup, size_t nsup)
+{
+	struct nilfs_argv argv;
+
+	if (nilfs->n_iocfd < 0) {
+		errno = EBADF;
+		return -1;
+	}
+
+	argv.v_base = (unsigned long)sup;
+	argv.v_nmembs = nsup;
+	argv.v_size = sizeof(struct nilfs_suinfo_update);
+	argv.v_index = 0;
+	argv.v_flags = 0;
+	if (ioctl(nilfs->n_iocfd, NILFS_IOCTL_SET_SUINFO, &argv) < 0)
+		return -1;
+	return argv.v_nmembs;
+}
+
+/**
  * nilfs_get_sustat -
  * @nilfs:
  * @sustat:
Signature · 6 lines
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 72f8c37258d08ba9793b0c1bb0374dd8efcd4756.1390310509.git.andreas.rohner-hi6Y0CQ0nG0@public.gmane.org

#20 lore raw

Re: [PATCH v2 4/5] nilfs-utils: add support for NILFS_IOCTL_SET_SUINFO ioctl

On Jan 21, 2014, at 4:59 PM, Andreas Rohner wrote:

[snip]

Quoted 34 lines
lib/gc.c +11 -1
index 0b0e2d6..ebbe0ca 100644
@@ -29,6 +29,10 @@
 #include <syslog.h>
 #endif	/* HAVE_SYSLOG_H */
 
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif	/* HAVE_SYS_TIME */
+
 #include <errno.h>
 #include <assert.h>
 #include <stdarg.h>
@@ -615,7 +619,10 @@ ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
 {
 	struct nilfs_vector *vdescv, *bdescv, *periodv, *vblocknrv;
 	sigset_t sigset, oldset, waitset;
-	ssize_t n, ret = -1;
+	ssize_t n, i, ret = -1;
+	__u32 freeblocks;
+	struct nilfs_suinfo_update *supv;
+	struct timeval tv;
 
 	if (nsegs == 0)
 		return 0;
@@ -678,6 +685,41 @@ ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
 		goto out_lock;
 	}
 
+	freeblocks = (nilfs_get_blocks_per_segment(nilfs) * n)
+				- (nilfs_vector_get_size(vdescv)
+				+ nilfs_vector_get_size(bdescv));

lib/gc.c ssize_t nilfs_reclaim_segment(struct nilfs *nilfs, · line 700

Quoted 10 lines
lib/gc.c +10 -0
+
+	/* if there are less free blocks than the
+	 * minimal threshold try to update suinfo
+	 * instead of cleaning */
+	if (freeblocks < minblocks * n) {
+		ret = gettimeofday(&tv, NULL);
+		if (ret < 0)
+			goto out_lock;
+
+		supv = malloc(sizeof(struct nilfs_suinfo_update) * n);

Is it enough to allocate memory without zeroing? Do you free allocated memory in the case of error?

Thanks,
Vyacheslav Dubeyko.

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 62FA32DB-83AC-4570-BD73-618C169390FE-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org

#22 lore raw

Re: [PATCH v2 4/5] nilfs-utils: add support for NILFS_IOCTL_SET_SUINFO ioctl

Quoted 35 lines · Vyacheslav Dubeyko

On Jan 21, 2014, at 4:59 PM, Andreas Rohner wrote:

[snip]

Quoted 31 lines
lib/gc.c +8 -1
index 0b0e2d6..ebbe0ca 100644
@@ -29,6 +29,10 @@
 #include <syslog.h>
 #endif	/* HAVE_SYSLOG_H */
 
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif	/* HAVE_SYS_TIME */
+
 #include <errno.h>
 #include <assert.h>
 #include <stdarg.h>
@@ -615,7 +619,10 @@ ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
 {
 	struct nilfs_vector *vdescv, *bdescv, *periodv, *vblocknrv;
 	sigset_t sigset, oldset, waitset;
-	ssize_t n, ret = -1;
+	ssize_t n, i, ret = -1;
+	__u32 freeblocks;
+	struct nilfs_suinfo_update *supv;
+	struct timeval tv;
 
 	if (nsegs == 0)
 		return 0;
@@ -678,6 +685,41 @@ ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
 		goto out_lock;
 	}
 
Quoted 15 lines

lib/gc.c ssize_t nilfs_reclaim_segment(struct nilfs *nilfs, · line 700

Quoted 13 lines
lib/gc.c +13 -0
+	freeblocks = (nilfs_get_blocks_per_segment(nilfs) * n)
+				- (nilfs_vector_get_size(vdescv)
+				+ nilfs_vector_get_size(bdescv));
+
+	/* if there are less free blocks than the
+	 * minimal threshold try to update suinfo
+	 * instead of cleaning */
+	if (freeblocks < minblocks * n) {
+		ret = gettimeofday(&tv, NULL);
+		if (ret < 0)
+			goto out_lock;
+
+		supv = malloc(sizeof(struct nilfs_suinfo_update) * n);

Is it enough to allocate memory without zeroing?

I use the flags to indicate, which parts of the structure are valid. I don't need to zero everything.

Quoted 1 line

Do you free allocated memory in the case of error?

Yes I immediately free it before I check the return value. Could you please read the code a bit more carefully, before you ask such questions?

br,
Andreas Rohner
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): [email protected]

#24 lore raw

Re: [PATCH v2 4/5] nilfs-utils: add support for NILFS_IOCTL_SET_SUINFO ioctl

Quoted 5 lines · Andreas Rohner
Quoted 2 lines

Do you free allocated memory in the case of error?

Yes I immediately free it before I check the return value. Could you please read the code a bit more carefully, before you ask such questions?

+ freeblocks = (nilfs_get_blocks_per_segment(nilfs) * n)
+ - (nilfs_vector_get_size(vdescv)
+ + nilfs_vector_get_size(bdescv));
+
+ /* if there are less free blocks than the
+ * minimal threshold try to update suinfo
+ * instead of cleaning */
+ if (freeblocks < minblocks * n) {
+ ret = gettimeofday(&tv, NULL);
+ if (ret < 0)
+ goto out_lock;
+
+ supv = malloc(sizeof(struct nilfs_suinfo_update) * n);
^^^^^^ memory allocation
+ if (supv == NULL) {
+ ret = -1;
+ goto out_lock;
+ }
+
+ for (i = 0; i < n; ++i) {
+ supv[i].sup_segnum = segnums[i];
+ supv[i].sup_flags = 0;
+ nilfs_suinfo_update_set_lastmod(&supv[i]);
+ supv[i].sup_sui.sui_lastmod = tv.tv_sec;
+ }
+
+ ret = nilfs_set_suinfo(nilfs, supv, n);
+ free(supv);
^^^^ memory freeing
+ if (ret >= 0) {
+ /* success, tell caller
+ * to try another segment/s */
+ ret = -EGCTRYAGAIN;
+ goto out_lock;
+ }
+ }
+

Ok. But I can suggest to free memory in the place of error processing (goto out_lock) and at the end of function for success. Otherwise, it looks like hiding free() call. And it is very easy to forget about memory freeing. It is good practice, I suppose, to group memory freeing operations.

Thanks,
Vyacheslav Dubeyko.

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#25 lore raw

Re: [PATCH v2 4/5] nilfs-utils: add support for NILFS_IOCTL_SET_SUINFO ioctl

In reply to a message not in the archive
Quoted 152 lines · Andreas Rohner

With this ioctl the segment usage information in the SUFILE can be updated from userspace.

This is useful, because it allows the GC to modify and update segment usage entries for specific segments, which enables it to avoid unnecessary write operations.

If a segment needs to be cleaned, but there is no or very little free space to be gained, the cleaning operation basically degrades to needless expensive copying of data. In the end the only thing that changes is the location of the data and a timestamp in the segment usage info. With this ioctl the GC can skip the copying and update the segment usage entries directly instead.

Additionally this patch implements a simple check in nilfs_reclaim_segment. If the number of free blocks that can be gained by cleaning the segments is below the threshold of minblocks, it simply updates the segment usage information instead.

---
 include/nilfs.h     |  2 ++
 include/nilfs2_fs.h | 41 +++++++++++++++++++++++++++++++++++++++++
 lib/gc.c            | 44 +++++++++++++++++++++++++++++++++++++++++++-
 lib/nilfs.c         | 26 ++++++++++++++++++++++++++
 4 files changed, 112 insertions(+), 1 deletion(-)
include/nilfs.h +2 -0
index 56286a9..1e9b034 100644
@@ -299,6 +299,8 @@ int nilfs_delete_checkpoint(struct nilfs *, nilfs_cno_t);
 int nilfs_get_cpstat(const struct nilfs *, struct nilfs_cpstat *);
 ssize_t nilfs_get_suinfo(const struct nilfs *, __u64, struct nilfs_suinfo *,
 			 size_t);
+ssize_t nilfs_set_suinfo(const struct nilfs *, struct nilfs_suinfo_update *,
+			 size_t);
 int nilfs_get_sustat(const struct nilfs *, struct nilfs_sustat *);
 ssize_t nilfs_get_vinfo(const struct nilfs *, struct nilfs_vinfo *, size_t);
 ssize_t nilfs_get_bdescs(const struct nilfs *, struct nilfs_bdesc *, size_t);
include/nilfs2_fs.h +41 -0
index e674f44..181c482 100644
@@ -713,6 +713,45 @@ static inline int nilfs_suinfo_clean(const struct nilfs_suinfo *si)
 	return !si->sui_flags;
 }
 
+/**
+ * nilfs_suinfo_update - segment usage information update
+ * @sup_segnum: segment number
+ * @sup_flags: flags for which fields are active in sup_sui
+ * @sup_sui: segment usage information
+ */
+struct nilfs_suinfo_update {
+	__u64 sup_segnum;
+	__u32 sup_flags;
+	struct nilfs_suinfo sup_sui;
+};
+
+enum {
+	NILFS_SUINFO_UPDATE_LASTMOD,
+	NILFS_SUINFO_UPDATE_NBLOCKS,
+	NILFS_SUINFO_UPDATE_FLAGS,
+};
+
+#define NILFS_SUINFO_UPDATE_FNS(flag, name)				\
+static inline void							\
+nilfs_suinfo_update_set_##name(struct nilfs_suinfo_update *sup)		\
+{									\
+	sup->sup_flags |= 1UL << NILFS_SUINFO_UPDATE_##flag;		\
+}									\
+static inline void							\
+nilfs_suinfo_update_clear_##name(struct nilfs_suinfo_update *sup)	\
+{									\
+	sup->sup_flags &= ~(1UL << NILFS_SUINFO_UPDATE_##flag);		\
+}									\
+static inline int							\
+nilfs_suinfo_update_##name(const struct nilfs_suinfo_update *sup)	\
+{									\
+	return !!(sup->sup_flags & (1UL << NILFS_SUINFO_UPDATE_##flag));\
+}
+
+NILFS_SUINFO_UPDATE_FNS(LASTMOD, lastmod)
+NILFS_SUINFO_UPDATE_FNS(NBLOCKS, nblocks)
+NILFS_SUINFO_UPDATE_FNS(FLAGS, flags)
+
 /* ioctl */
 enum {
 	NILFS_CHECKPOINT,
@@ -867,5 +906,7 @@ struct nilfs_bdesc {
 	_IOW(NILFS_IOCTL_IDENT, 0x8B, __u64)
 #define NILFS_IOCTL_SET_ALLOC_RANGE  \
 	_IOW(NILFS_IOCTL_IDENT, 0x8C, __u64[2])
+#define NILFS_IOCTL_SET_SUINFO  \
+	_IOW(NILFS_IOCTL_IDENT, 0x8D, struct nilfs_argv)
 
 #endif	/* _LINUX_NILFS_FS_H */
lib/gc.c +31 -1
index 0b0e2d6..ebbe0ca 100644
@@ -29,6 +29,10 @@
 #include <syslog.h>
 #endif	/* HAVE_SYSLOG_H */
 
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif	/* HAVE_SYS_TIME */
+
 #include <errno.h>
 #include <assert.h>
 #include <stdarg.h>
@@ -615,7 +619,10 @@ ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
 {
 	struct nilfs_vector *vdescv, *bdescv, *periodv, *vblocknrv;
 	sigset_t sigset, oldset, waitset;
-	ssize_t n, ret = -1;
+	ssize_t n, i, ret = -1;
+	__u32 freeblocks;
+	struct nilfs_suinfo_update *supv;
+	struct timeval tv;
 
 	if (nsegs == 0)
 		return 0;
@@ -678,6 +685,41 @@ ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
 		goto out_lock;
 	}
 
+	freeblocks = (nilfs_get_blocks_per_segment(nilfs) * n)
+				- (nilfs_vector_get_size(vdescv)
+				+ nilfs_vector_get_size(bdescv));
+
+	/* if there are less free blocks than the
+	 * minimal threshold try to update suinfo
+	 * instead of cleaning */
+	if (freeblocks < minblocks * n) {
+		ret = gettimeofday(&tv, NULL);
+		if (ret < 0)
+			goto out_lock;
+
+		supv = malloc(sizeof(struct nilfs_suinfo_update) * n);
+		if (supv == NULL) {
+			ret = -1;
+			goto out_lock;
+		}
+
+		for (i = 0; i < n; ++i) {
+			supv[i].sup_segnum = segnums[i];
+			supv[i].sup_flags = 0;
+			nilfs_suinfo_update_set_lastmod(&supv[i]);
+			supv[i].sup_sui.sui_lastmod = tv.tv_sec;

lib/gc.c ssize_t nilfs_reclaim_segment(struct nilfs *nilfs, · line 720

Quoted 10 lines
lib/gc.c +10 -0
+		}
+
+		ret = nilfs_set_suinfo(nilfs, supv, n);
+		free(supv);
+		if (ret >= 0) {
+			/* success, tell caller
+			 * to try another segment/s */
+			ret = -EGCTRYAGAIN;
+			goto out_lock;
+		}

You should design the new reclaim function so that it turns off the logic using nilfs_set_suinfo() once nilfs_set_suinfo() returned a status code < 0 and errno was ENOTTY.

This fallback logic is needed to keep compatibility for old kernel.

In addition, whether applying the optimization or not, should be selectable in /etc/nilfs_cleanerd.conf.

Quoted 10 lines
lib/gc.c +2 -0
+	}
+
 	ret = nilfs_clean_segments(nilfs,
 				   nilfs_vector_get_data(vdescv),
 				   nilfs_vector_get_size(vdescv),
lib/nilfs.c +0 -0
index 7265830..dbd03e6 100644

lib/nilfs.c ssize_t nilfs_get_suinfo(const struct nilfs *nilfs, __u64 segnum, · line 552

Quoted 5 lines
lib/nilfs.c +2 -0
@@ -548,6 +548,32 @@ ssize_t nilfs_get_suinfo(const struct nilfs *nilfs, __u64 segnum,
 }
 
 /**
+ * nilfs_set_suinfo -
+ * @nilfs:

Please fill the summary line of this function.

I'll continue reviewing this patchset tomorrow.

Regards,
Ryusuke Konishi

Quoted 34 lines
lib/nilfs.c +24 -0
+ * @sup: an array of nilfs_suinfo_update structs
+ * @nsup: number of elements in sup
+ */
+ssize_t nilfs_set_suinfo(const struct nilfs *nilfs,
+			 struct nilfs_suinfo_update *sup, size_t nsup)
+{
+	struct nilfs_argv argv;
+
+	if (nilfs->n_iocfd < 0) {
+		errno = EBADF;
+		return -1;
+	}
+
+	argv.v_base = (unsigned long)sup;
+	argv.v_nmembs = nsup;
+	argv.v_size = sizeof(struct nilfs_suinfo_update);
+	argv.v_index = 0;
+	argv.v_flags = 0;
+	if (ioctl(nilfs->n_iocfd, NILFS_IOCTL_SET_SUINFO, &argv) < 0)
+		return -1;
+	return argv.v_nmembs;
+}
+
+/**
  * nilfs_get_sustat -
  * @nilfs:
  * @sustat:
Signature · 6 lines
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 20140125.032633.184837411.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org

#27 lore raw

Re: [PATCH v2 4/5] nilfs-utils: add support for NILFS_IOCTL_SET_SUINFO ioctl

Quoted 38 lines · Ryusuke Konishi
Quoted 23 lines
lib/gc.c +23 -0
+	freeblocks = (nilfs_get_blocks_per_segment(nilfs) * n)
+				- (nilfs_vector_get_size(vdescv)
+				+ nilfs_vector_get_size(bdescv));
+
+	/* if there are less free blocks than the
+	 * minimal threshold try to update suinfo
+	 * instead of cleaning */
+	if (freeblocks < minblocks * n) {
+		ret = gettimeofday(&tv, NULL);
+		if (ret < 0)
+			goto out_lock;
+
+		supv = malloc(sizeof(struct nilfs_suinfo_update) * n);
+		if (supv == NULL) {
+			ret = -1;
+			goto out_lock;
+		}
+
+		for (i = 0; i < n; ++i) {
+			supv[i].sup_segnum = segnums[i];
+			supv[i].sup_flags = 0;
+			nilfs_suinfo_update_set_lastmod(&supv[i]);
+			supv[i].sup_sui.sui_lastmod = tv.tv_sec;

lib/gc.c ssize_t nilfs_reclaim_segment(struct nilfs *nilfs, · line 720

Quoted 10 lines
lib/gc.c +10 -0
+		}
+
+		ret = nilfs_set_suinfo(nilfs, supv, n);
+		free(supv);
+		if (ret >= 0) {
+			/* success, tell caller
+			 * to try another segment/s */
+			ret = -EGCTRYAGAIN;
+			goto out_lock;
+		}

You should design the new reclaim function so that it turns off the logic using nilfs_set_suinfo() once nilfs_set_suinfo() returned a status code < 0 and errno was ENOTTY.

Quoted 1 line

This fallback logic is needed to keep compatibility for old kernel.

Thanks for your review. I am quite devastated how much needs to be fixed :). I implemented most of your suggestions. I will test them tomorrow and compose a new version of the patch set.

Quoted 2 lines

In addition, whether applying the optimization or not, should be selectable in /etc/nilfs_cleanerd.conf.

You can set the two options to 0, which would completely disable the optimization.

# Minimum number of free blocks before a segment

# can be cleaned. Set to 0 to disable it.
min_free_blocks_threshold	0

# Minimum number of free blocks before a segment

# can be cleaned. Set to 0 to disable it.
# if clean segments < min_clean_segments
mc_min_free_blocks_threshold	0

Is that enough or should I add an additional switch, like the use_mmap switch?

br,
Andreas Rohner
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): [email protected]

#29 lore raw

Re: [PATCH v2 4/5] nilfs-utils: add support for NILFS_IOCTL_SET_SUINFO ioctl

Quoted 21 lines · Andreas Rohner
Quoted 5 lines · Ryusuke Konishi

You should design the new reclaim function so that it turns off the logic using nilfs_set_suinfo() once nilfs_set_suinfo() returned a status code < 0 and errno was ENOTTY.

This fallback logic is needed to keep compatibility for old kernel.

Thanks for your review. I am quite devastated how much needs to be fixed :). I implemented most of your suggestions. I will test them tomorrow and compose a new version of the patch set.

Quoted 2 lines

In addition, whether applying the optimization or not, should be selectable in /etc/nilfs_cleanerd.conf.

You can set the two options to 0, which would completely disable the optimization.

# Minimum number of free blocks before a segment

# can be cleaned. Set to 0 to disable it.
min_free_blocks_threshold	0
Quoted 7 lines

# Minimum number of free blocks before a segment

# can be cleaned. Set to 0 to disable it.
# if clean segments < min_clean_segments
mc_min_free_blocks_threshold	0

Is that enough or should I add an additional switch, like the use_mmap switch?

Yes, please do so. The flag name would be "use_set_suinfo" (NILFS_OPT_SET_SUINFO flag for nilfs object)

If nilfs_set_suinfo() returned error with errno=ENOTTY, the gc library should automatically turns it off (with a warning message).

If NILFS_OPT_SET_SUINFO was off from the start, this optimization should be never tried regardless of the above threshold values.

And, for the above theshold declarations, proper default values should be written in nilfs_cleanerd.conf.

Regards,
Ryusuke Konishi
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#30 lore raw

Re: [PATCH v2 4/5] nilfs-utils: add support for NILFS_IOCTL_SET_SUINFO ioctl

In reply to a message not in the archive
Quoted 9 lines · Andreas Rohner
Quoted 8 lines · Ryusuke Konishi

lib/gc.c ssize_t nilfs_reclaim_segment(struct nilfs *nilfs, · line 720

Quoted 8 lines
lib/gc.c +8 -0
+		ret = nilfs_set_suinfo(nilfs, supv, n);
+		free(supv);
+		if (ret >= 0) {
+			/* success, tell caller
+			 * to try another segment/s */
+			ret = -EGCTRYAGAIN;
+			goto out_lock;
+		}

Returning -EGCTRYAGAIN looks confusing, since posix error code Exxxxx is usually stored in errno variable in userland. It also looks a bit hacky.

How about handling this as follows ?

- Add a new structure to return result of GC, for instance, as follows:

struct nilfs_reclaim_status {
unsigned int ncleanedsegs; /* number of segments cleaned
with nilfs_clean_segments() */
unsigned int ndeferredsegs;/* number of segments deferred
with nilfs_set_suinfo() */
unsigned long nliveblocks; /* sum of live virtual blocks and live
DAT blocks */
unsigned long ndeadblocks; /* number of reclaimable blocks */
unsigned long nlivevblocks; /* live virtual blocks */
unsigned long nfreevblocks; /* freed virtual block addresses */
...
};

- Use the structure as an argument of the "new" API function (i.e. variant of nilfs_reclaim_segment() )

- Rewrite the variant API function so that it returns a success value
(0) also for the EGCTRYAGAIN case.

- Store other status information in nilfs_reclaim_status structures.

And, I think adding nilfs_set_suinfo() API should be a separate patch.

Regards,
Ryusuke Konishi
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 20140126.190004.443429632.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org

#32 lore raw

Re: [PATCH v2 4/5] nilfs-utils: add support for NILFS_IOCTL_SET_SUINFO ioctl

Quoted 14 lines · Ryusuke Konishi
Quoted 9 lines · Andreas Rohner
Quoted 8 lines · Ryusuke Konishi

Review

Quoted 8 lines
(quoted diff) +8 -0
+		ret = nilfs_set_suinfo(nilfs, supv, n);
+		free(supv);
+		if (ret >= 0) {
+			/* success, tell caller
+			 * to try another segment/s */
+			ret = -EGCTRYAGAIN;
+			goto out_lock;
+		}

Returning -EGCTRYAGAIN looks confusing, since posix error code Exxxxx is usually stored in errno variable in userland. It also looks a bit hacky.

True. Vyacheslav had similar concerns.

Quoted 21 lines

How about handling this as follows ?

- Add a new structure to return result of GC, for instance, as follows:

struct nilfs_reclaim_status {
unsigned int ncleanedsegs; /* number of segments cleaned
with nilfs_clean_segments() */
unsigned int ndeferredsegs;/* number of segments deferred
with nilfs_set_suinfo() */
unsigned long nliveblocks; /* sum of live virtual blocks and live
DAT blocks */
unsigned long ndeadblocks; /* number of reclaimable blocks */
unsigned long nlivevblocks; /* live virtual blocks */
unsigned long nfreevblocks; /* freed virtual block addresses */
...
};

- Use the structure as an argument of the "new" API function (i.e. variant of nilfs_reclaim_segment() )

Quoted 7 lines

- Rewrite the variant API function so that it returns a success value
(0) also for the EGCTRYAGAIN case.

- Store other status information in nilfs_reclaim_status structures.

And, I think adding nilfs_set_suinfo() API should be a separate patch.

Yes EGCTRYAGAIN is not necessary for the nilfs_set_suinfo() API to work. It is a good idea to use a separate patch for this.

br,
Andreas Rohner

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#33 lore raw

PATCH v2 5/5 nilfs-utils: man: add description of min_free_blocks_threshold

In reply to a message not in the archive

Adds a description of the new min_free_blocks_threshold and mc_min_free_blocks_threshold options in the config file and the new command line parameter -t for nilfs-clean.

---
 man/nilfs-clean.8         | 4 ++++
 man/nilfs_cleanerd.conf.5 | 9 +++++++++
 2 files changed, 13 insertions(+)
man/nilfs-clean.8 +4 -0
index 04e11c6..5af836e 100644
@@ -67,6 +67,10 @@ until user resumes the garbage collection.
 \fB\-S\fR, \fB\-\-speed=\fICOUNT[/SECONDS]\fR
 Set garbage collection speed for a cleaner run.
 .TP
+\fB\-t\fR, \fB\-\-free\-blocks\-threshold=\fICOUNT\fR
+Specify the minimal number of free blocks before a segment can be
+cleaned
+.TP
 \fB\-v\fR, \fB\-\-verbose\fR
 Verbose mode.
 .TP
man/nilfs_cleanerd.conf.5 +9 -0
index 8f3fcd2..ccb0ade 100644
@@ -79,6 +79,15 @@ Specify whether to use \fBmmap\fP(2) for reading segments.  At
 present, this option is enabled if supported regardless of this
 directive.
 .TP
+.B min_free_blocks_threshold
+Specify the minimal number of free blocks before a segment can be
+cleaned. Set to 0 to disable it. The default value is 256.
+.TP
+.B mc_min_free_blocks_threshold
+Specify the minimal number of free blocks before a segment can be
+cleaned if clean segments < min_clean_segments. Set to 0 to disable it.
+The default value is 128.
+.TP
 .B log_priority
 Gives the verbosity level that is used when logging messages from
 \fBnilfs_cleanerd\fP(8).  The possible values are: \fBemerg\fP,
Signature · 6 lines
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#34 lore raw

PATCH v2 1/3 nilfs2: add new nilfs_suinfo_update struct

In reply to a message not in the archive

This adds struct nilfs_suinfo_update and some flags. It contains the information needed to update one entry of segment usage information in the SUFILE. The flags specify, which fields need to be updated.

This can be used to update segment usage information from userspace with an ioctl.

---
 include/linux/nilfs2_fs.h | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)
include/linux/nilfs2_fs.h +39 -0
index 9875576..2ee1594 100644
@@ -709,6 +709,45 @@ static inline int nilfs_suinfo_clean(const struct nilfs_suinfo *si)
 	return !si->sui_flags;
 }
 
+/**
+ * nilfs_suinfo_update - segment usage information update
+ * @sup_segnum: segment number
+ * @sup_flags: flags for which fields are active in sup_sui
+ * @sup_sui: segment usage information
+ */
+struct nilfs_suinfo_update {
+	__u64 sup_segnum;
+	__u32 sup_flags;
+	struct nilfs_suinfo sup_sui;
+};
+
+enum {
+	NILFS_SUINFO_UPDATE_LASTMOD,
+	NILFS_SUINFO_UPDATE_NBLOCKS,
+	NILFS_SUINFO_UPDATE_FLAGS,
+};
+
+#define NILFS_SUINFO_UPDATE_FNS(flag, name)				\
+static inline void							\
+nilfs_suinfo_update_set_##name(struct nilfs_suinfo_update *sup)		\
+{									\
+	sup->sup_flags |= 1UL << NILFS_SUINFO_UPDATE_##flag;		\
+}									\
+static inline void							\
+nilfs_suinfo_update_clear_##name(struct nilfs_suinfo_update *sup)	\
+{									\
+	sup->sup_flags &= ~(1UL << NILFS_SUINFO_UPDATE_##flag);		\
+}									\
+static inline int							\
+nilfs_suinfo_update_##name(const struct nilfs_suinfo_update *sup)	\
+{									\
+	return !!(sup->sup_flags & (1UL << NILFS_SUINFO_UPDATE_##flag));\
+}
+
+NILFS_SUINFO_UPDATE_FNS(LASTMOD, lastmod)
+NILFS_SUINFO_UPDATE_FNS(NBLOCKS, nblocks)
+NILFS_SUINFO_UPDATE_FNS(FLAGS, flags)
+
 /* ioctl */
 enum {
 	NILFS_CHECKPOINT,
Signature · 6 lines
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): cec6a449ddf5ae9da2928cdddfb96ebcb2789eee.1390312777.git.andreas.rohner-hi6Y0CQ0nG0@public.gmane.org

#36 lore raw

PATCH v2 2/3 nilfs2: add nilfs_sufile_set_suinfo to update segment usage info

This patch introduces the nilfs_sufile_set_suinfo function, which expects an array of nilfs_suinfo_update structures and updates the segment usage information accordingly.

This is basically a helper function for the newly introduced NILFS_IOCTL_SET_SUINFO ioctl.

---
 fs/nilfs2/sufile.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/nilfs2/sufile.h |  2 +-
 2 files changed, 92 insertions(+), 1 deletion(-)
fs/nilfs2/sufile.c +91 -0
index 3127e9f..81c3438 100644
@@ -870,6 +870,97 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
 }
 
 /**
+ * nilfs_sufile_set_suinfo -
+ * @sufile: inode of segment usage file
+ * @buf: array of suinfo
+ * @supsz: byte size of suinfo
+ * @nsup: size of suinfo array
+ *
+ * Description: Takes an array of nilfs_suinfo_update structs and updates
+ * segment usage accordingly.
+ *
+ * Return Value: On success, 0 is returned and .... On error, one of the
+ * following negative error codes is returned.
+ *
+ * %-EIO - I/O error.
+ *
+ * %-ENOMEM - Insufficient amount of memory available.
+ *
+ * %-EINVAL - Invalid segment number in input
+ */
+ssize_t nilfs_sufile_set_suinfo(struct inode *sufile, void *buf,
+				unsigned supsz, size_t nsup)
+{
+	struct buffer_head *bh;
+	struct nilfs_suinfo_update *sup, *supv = buf;
+	struct nilfs_segment_usage *su;
+	void *kaddr;
+	unsigned long blkoff, prev_blkoff;
+	size_t nerr = 0;
+	int ret = 0;
+
+	if (unlikely(nsup == 0))
+		goto out;
+
+	down_write(&NILFS_MDT(sufile)->mi_sem);
+	for (sup = supv; sup < supv + nsup; sup++) {
+		if (unlikely(sup->sup_segnum >=
+				nilfs_sufile_get_nsegments(sufile))) {
+			printk(KERN_WARNING
+			       "%s: invalid segment number: %llu\n", __func__,
+			       (unsigned long long)sup->sup_segnum);
+			nerr++;
+		}
+	}
+	if (nerr > 0) {
+		ret = -EINVAL;
+		goto out_sem;
+	}
+
+	sup = supv;
+	blkoff = nilfs_sufile_get_blkoff(sufile, sup->sup_segnum);
+	ret = nilfs_mdt_get_block(sufile, blkoff, 1, NULL, &bh);
+	if (ret < 0)
+		goto out_sem;
+
+	for (;;) {
+		kaddr = kmap_atomic(bh->b_page);
+		su = nilfs_sufile_block_get_segment_usage(
+			sufile, sup->sup_segnum, bh, kaddr);
+
+		if (nilfs_suinfo_update_lastmod(sup))
+			su->su_lastmod = cpu_to_le64(sup->sup_sui.sui_lastmod);
+
+		if (nilfs_suinfo_update_nblocks(sup))
+			su->su_nblocks = cpu_to_le32(sup->sup_sui.sui_nblocks);
+
+		if (nilfs_suinfo_update_flags(sup))
+			su->su_flags = cpu_to_le32(sup->sup_sui.sui_flags);
+
+		kunmap_atomic(kaddr);
+
+		if (++sup >= supv + nsup)
+			break;
+		prev_blkoff = blkoff;
+		blkoff = nilfs_sufile_get_blkoff(sufile, sup->sup_segnum);
+		if (blkoff == prev_blkoff)
+			continue;
+
+		/* get different block */
+		brelse(bh);
+		ret = nilfs_mdt_get_block(sufile, blkoff, 1, NULL, &bh);
+		if (unlikely(ret < 0))
+			goto out_sem;
+	}
+	brelse(bh);
+
+ out_sem:
+	up_write(&NILFS_MDT(sufile)->mi_sem);
+ out:
+	return ret;
+}
+
+/**
  * nilfs_sufile_read - read or get sufile inode
  * @sb: super block instance
  * @susize: size of a segment usage entry
fs/nilfs2/sufile.h +1 -1
index e84bc5b..7aa9d3e 100644
@@ -44,7 +44,7 @@ int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,
 int nilfs_sufile_get_stat(struct inode *, struct nilfs_sustat *);
 ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, void *, unsigned,
 				size_t);
-
+ssize_t nilfs_sufile_set_suinfo(struct inode *, void *, unsigned , size_t);
 int nilfs_sufile_updatev(struct inode *, __u64 *, size_t, int, size_t *,
 			 void (*dofunc)(struct inode *, __u64,
 					struct buffer_head *,
Signature · 6 lines
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 2fd48b2d524a59a02bdad13c0c194de3e5b55cc7.1390312777.git.andreas.rohner-hi6Y0CQ0nG0@public.gmane.org

#38 lore raw

Re: [PATCH v2 2/3] nilfs2: add nilfs_sufile_set_suinfo to update segment usage info

Quoted 18 lines · Andreas Rohner

This patch introduces the nilfs_sufile_set_suinfo function, which expects an array of nilfs_suinfo_update structures and updates the segment usage information accordingly.

This is basically a helper function for the newly introduced NILFS_IOCTL_SET_SUINFO ioctl.

---
 fs/nilfs2/sufile.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/nilfs2/sufile.h |  2 +-
 2 files changed, 92 insertions(+), 1 deletion(-)
fs/nilfs2/sufile.c +0 -0
index 3127e9f..81c3438 100644

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 873

Quoted 4 lines
fs/nilfs2/sufile.c +1 -0
@@ -870,6 +870,97 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
 }
 
 /**
+ * nilfs_sufile_set_suinfo -

Please fill the summary line of function even though nilfs_sufile_get_suinfo() function lacks it.

* nilfs_sufile_set_suinfo - update segment usage information

Quoted 35 lines
fs/nilfs2/sufile.c +35 -0
+ * @sufile: inode of segment usage file
+ * @buf: array of suinfo
+ * @supsz: byte size of suinfo
+ * @nsup: size of suinfo array
+ *
+ * Description: Takes an array of nilfs_suinfo_update structs and updates
+ * segment usage accordingly.
+ *
+ * Return Value: On success, 0 is returned and .... On error, one of the
+ * following negative error codes is returned.
+ *
+ * %-EIO - I/O error.
+ *
+ * %-ENOMEM - Insufficient amount of memory available.
+ *
+ * %-EINVAL - Invalid segment number in input
+ */
+ssize_t nilfs_sufile_set_suinfo(struct inode *sufile, void *buf,
+				unsigned supsz, size_t nsup)
+{
+	struct buffer_head *bh;
+	struct nilfs_suinfo_update *sup, *supv = buf;
+	struct nilfs_segment_usage *su;
+	void *kaddr;
+	unsigned long blkoff, prev_blkoff;
+	size_t nerr = 0;
+	int ret = 0;
+
+	if (unlikely(nsup == 0))
+		goto out;
+
+	down_write(&NILFS_MDT(sufile)->mi_sem);
+	for (sup = supv; sup < supv + nsup; sup++) {
+		if (unlikely(sup->sup_segnum >=
+				nilfs_sufile_get_nsegments(sufile))) {

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 918

Quoted 10 lines
fs/nilfs2/sufile.c +10 -0
+			printk(KERN_WARNING
+			       "%s: invalid segment number: %llu\n", __func__,
+			       (unsigned long long)sup->sup_segnum);
+			nerr++;
+		}
+	}
+	if (nerr > 0) {
+		ret = -EINVAL;
+		goto out_sem;
+	}

Seems that you can exit from inside the loop:

	for (sup = supv; sup < supv + nsup; sup++) {
		if (unlikely(sup->sup_segnum >=
				nilfs_sufile_get_nsegments(sufile))) {
			printk(KERN_WARNING
			       "%s: invalid segment number: %llu\n", __func__,
			       (unsigned long long)sup->sup_segnum);
			ret = -EINVAL;
			goto out_sem;
		}
	}
Quoted 10 lines
fs/nilfs2/sufile.c +10 -0
+
+	sup = supv;
+	blkoff = nilfs_sufile_get_blkoff(sufile, sup->sup_segnum);
+	ret = nilfs_mdt_get_block(sufile, blkoff, 1, NULL, &bh);
+	if (ret < 0)
+		goto out_sem;
+
+	for (;;) {
+		kaddr = kmap_atomic(bh->b_page);
+		su = nilfs_sufile_block_get_segment_usage(

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 938

Quoted 10 lines
fs/nilfs2/sufile.c +10 -0
+			sufile, sup->sup_segnum, bh, kaddr);
+
+		if (nilfs_suinfo_update_lastmod(sup))
+			su->su_lastmod = cpu_to_le64(sup->sup_sui.sui_lastmod);
+
+		if (nilfs_suinfo_update_nblocks(sup))
+			su->su_nblocks = cpu_to_le32(sup->sup_sui.sui_nblocks);
+
+		if (nilfs_suinfo_update_flags(sup))
+			su->su_flags = cpu_to_le32(sup->sup_sui.sui_flags);

You must also update the counter value of sh_ncleansegs, sh_ndirtysegs in the nilfs_sufile_header struct of sufile header block based on the change of these flags.

In addition, you should ignore NILFS_SEGMENT_USAGE_ACTIVE_FLAG as below because this flag is a virtual flag set by running nilfs kernel code. The flag bit should not be written to sufile on disk.

          (sui_flags & ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE))

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 942

Quoted 4 lines
fs/nilfs2/sufile.c +4 -0
+
+		kunmap_atomic(kaddr);
+
+		if (++sup >= supv + nsup)

You must not use the automatic pointer operation of C language for nilfs_suinfo_update because it may be extended in a future release. This "++sup" breaks forward compatibility of the ioctl.

You should do this by:

                sup = (void *)sup + supsz;

Note that pointer type is automatically converted for "void *" type variables.

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 949

Quoted 7 lines
fs/nilfs2/sufile.c +7 -0
+			break;
+		prev_blkoff = blkoff;
+		blkoff = nilfs_sufile_get_blkoff(sufile, sup->sup_segnum);
+		if (blkoff == prev_blkoff)
+			continue;
+
+		/* get different block */

You must mark bh that this function changed as dirty with mark_buffer_dirty(bh). Otherwise, the change will be gone.

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 956

Quoted 7 lines
fs/nilfs2/sufile.c +7 -0
+		brelse(bh);
+		ret = nilfs_mdt_get_block(sufile, blkoff, 1, NULL, &bh);
+		if (unlikely(ret < 0))
+			goto out_sem;
+	}
+	brelse(bh);
+

The sufile should be marked as dirty (if any change happened):

    nilfs_mdt_mark_dirty(sufile);
Quoted 30 lines
fs/nilfs2/sufile.c +7 -0
+ out_sem:
+	up_write(&NILFS_MDT(sufile)->mi_sem);
+ out:
+	return ret;
+}
+
+/**
  * nilfs_sufile_read - read or get sufile inode
  * @sb: super block instance
  * @susize: size of a segment usage entry
fs/nilfs2/sufile.h +1 -1
index e84bc5b..7aa9d3e 100644
@@ -44,7 +44,7 @@ int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,
 int nilfs_sufile_get_stat(struct inode *, struct nilfs_sustat *);
 ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, void *, unsigned,
 				size_t);
-
+ssize_t nilfs_sufile_set_suinfo(struct inode *, void *, unsigned , size_t);
 int nilfs_sufile_updatev(struct inode *, __u64 *, size_t, int, size_t *,
 			 void (*dofunc)(struct inode *, __u64,
 					struct buffer_head *,
Signature · 6 lines
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 20140124.205623.400541300.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org

#40 lore raw

Re: [PATCH v2 2/3] nilfs2: add nilfs_sufile_set_suinfo to update segment usage info

Quoted 77 lines · Ryusuke Konishi
Quoted 18 lines · Andreas Rohner

This patch introduces the nilfs_sufile_set_suinfo function, which expects an array of nilfs_suinfo_update structures and updates the segment usage information accordingly.

This is basically a helper function for the newly introduced NILFS_IOCTL_SET_SUINFO ioctl.

---
 fs/nilfs2/sufile.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/nilfs2/sufile.h |  2 +-
 2 files changed, 92 insertions(+), 1 deletion(-)
fs/nilfs2/sufile.c +0 -0
index 3127e9f..81c3438 100644

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 873

Quoted 4 lines
fs/nilfs2/sufile.c +1 -0
@@ -870,6 +870,97 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
 }
 
 /**
+ * nilfs_sufile_set_suinfo -

Please fill the summary line of function even though nilfs_sufile_get_suinfo() function lacks it.

* nilfs_sufile_set_suinfo - update segment usage information

Quoted 35 lines
fs/nilfs2/sufile.c +35 -0
+ * @sufile: inode of segment usage file
+ * @buf: array of suinfo
+ * @supsz: byte size of suinfo
+ * @nsup: size of suinfo array
+ *
+ * Description: Takes an array of nilfs_suinfo_update structs and updates
+ * segment usage accordingly.
+ *
+ * Return Value: On success, 0 is returned and .... On error, one of the
+ * following negative error codes is returned.
+ *
+ * %-EIO - I/O error.
+ *
+ * %-ENOMEM - Insufficient amount of memory available.
+ *
+ * %-EINVAL - Invalid segment number in input
+ */
+ssize_t nilfs_sufile_set_suinfo(struct inode *sufile, void *buf,
+				unsigned supsz, size_t nsup)
+{
+	struct buffer_head *bh;
+	struct nilfs_suinfo_update *sup, *supv = buf;
+	struct nilfs_segment_usage *su;
+	void *kaddr;
+	unsigned long blkoff, prev_blkoff;
+	size_t nerr = 0;
+	int ret = 0;
+
+	if (unlikely(nsup == 0))
+		goto out;
+
+	down_write(&NILFS_MDT(sufile)->mi_sem);
+	for (sup = supv; sup < supv + nsup; sup++) {
+		if (unlikely(sup->sup_segnum >=
+				nilfs_sufile_get_nsegments(sufile))) {

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 918

Quoted 10 lines
fs/nilfs2/sufile.c +10 -0
+			printk(KERN_WARNING
+			       "%s: invalid segment number: %llu\n", __func__,
+			       (unsigned long long)sup->sup_segnum);
+			nerr++;
+		}
+	}
+	if (nerr > 0) {
+		ret = -EINVAL;
+		goto out_sem;
+	}

Seems that you can exit from inside the loop:

Quoted 10 lines
	for (sup = supv; sup < supv + nsup; sup++) {
		if (unlikely(sup->sup_segnum >=
				nilfs_sufile_get_nsegments(sufile))) {
			printk(KERN_WARNING
			       "%s: invalid segment number: %llu\n", __func__,
			       (unsigned long long)sup->sup_segnum);
			ret = -EINVAL;
			goto out_sem;
		}
	}

Yes. I copied that from nilfs_sufile_updatev.

Quoted 25 lines
Quoted 10 lines
fs/nilfs2/sufile.c +10 -0
+
+	sup = supv;
+	blkoff = nilfs_sufile_get_blkoff(sufile, sup->sup_segnum);
+	ret = nilfs_mdt_get_block(sufile, blkoff, 1, NULL, &bh);
+	if (ret < 0)
+		goto out_sem;
+
+	for (;;) {
+		kaddr = kmap_atomic(bh->b_page);
+		su = nilfs_sufile_block_get_segment_usage(

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 938

Quoted 10 lines
fs/nilfs2/sufile.c +10 -0
+			sufile, sup->sup_segnum, bh, kaddr);
+
+		if (nilfs_suinfo_update_lastmod(sup))
+			su->su_lastmod = cpu_to_le64(sup->sup_sui.sui_lastmod);
+
+		if (nilfs_suinfo_update_nblocks(sup))
+			su->su_nblocks = cpu_to_le32(sup->sup_sui.sui_nblocks);
+
+		if (nilfs_suinfo_update_flags(sup))
+			su->su_flags = cpu_to_le32(sup->sup_sui.sui_flags);

You must also update the counter value of sh_ncleansegs, sh_ndirtysegs in the nilfs_sufile_header struct of sufile header block based on the change of these flags.

Quoted 5 lines

In addition, you should ignore NILFS_SEGMENT_USAGE_ACTIVE_FLAG as below because this flag is a virtual flag set by running nilfs kernel code. The flag bit should not be written to sufile on disk.

          (sui_flags & ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE))

Yes. I didn't think of that.

Quoted 9 lines

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 942

Quoted 4 lines
fs/nilfs2/sufile.c +4 -0
+
+		kunmap_atomic(kaddr);
+
+		if (++sup >= supv + nsup)

You must not use the automatic pointer operation of C language for nilfs_suinfo_update because it may be extended in a future release. This "++sup" breaks forward compatibility of the ioctl.

Quoted 6 lines

You should do this by:

                sup = (void *)sup + supsz;

Note that pointer type is automatically converted for "void *" type variables.

Makes sense. I guess I blindly copied that from nilfs_sufile_updatev, but with a simple array of __u64 it works of course. With a structure, that is subject to change, not so much any more.

Quoted 22 lines

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 949

Quoted 7 lines
fs/nilfs2/sufile.c +7 -0
+			break;
+		prev_blkoff = blkoff;
+		blkoff = nilfs_sufile_get_blkoff(sufile, sup->sup_segnum);
+		if (blkoff == prev_blkoff)
+			continue;
+
+		/* get different block */

You must mark bh that this function changed as dirty with mark_buffer_dirty(bh). Otherwise, the change will be gone.

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 956

Quoted 7 lines
fs/nilfs2/sufile.c +7 -0
+		brelse(bh);
+		ret = nilfs_mdt_get_block(sufile, blkoff, 1, NULL, &bh);
+		if (unlikely(ret < 0))
+			goto out_sem;
+	}
+	brelse(bh);
+

The sufile should be marked as dirty (if any change happened):

Quoted 1 line
    nilfs_mdt_mark_dirty(sufile);

Of course. I am sorry that's a really stupid error. I will fix it right away.

Thanks for your review. I am really embarrassed about all the stupid avoidable errors.

br,
Andreas Rohner
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): [email protected]

#42 lore raw

Re: [PATCH v2 2/3] nilfs2: add nilfs_sufile_set_suinfo to update segment usage info

Quoted 78 lines · Andreas Rohner
Quoted 77 lines · Ryusuke Konishi
Quoted 18 lines · Andreas Rohner

This patch introduces the nilfs_sufile_set_suinfo function, which expects an array of nilfs_suinfo_update structures and updates the segment usage information accordingly.

This is basically a helper function for the newly introduced NILFS_IOCTL_SET_SUINFO ioctl.

---
 fs/nilfs2/sufile.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/nilfs2/sufile.h |  2 +-
 2 files changed, 92 insertions(+), 1 deletion(-)
fs/nilfs2/sufile.c +0 -0
index 3127e9f..81c3438 100644

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 873

Quoted 4 lines
fs/nilfs2/sufile.c +1 -0
@@ -870,6 +870,97 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
 }
 
 /**
+ * nilfs_sufile_set_suinfo -

Please fill the summary line of function even though nilfs_sufile_get_suinfo() function lacks it.

* nilfs_sufile_set_suinfo - update segment usage information

Quoted 35 lines
fs/nilfs2/sufile.c +35 -0
+ * @sufile: inode of segment usage file
+ * @buf: array of suinfo
+ * @supsz: byte size of suinfo
+ * @nsup: size of suinfo array
+ *
+ * Description: Takes an array of nilfs_suinfo_update structs and updates
+ * segment usage accordingly.
+ *
+ * Return Value: On success, 0 is returned and .... On error, one of the
+ * following negative error codes is returned.
+ *
+ * %-EIO - I/O error.
+ *
+ * %-ENOMEM - Insufficient amount of memory available.
+ *
+ * %-EINVAL - Invalid segment number in input
+ */
+ssize_t nilfs_sufile_set_suinfo(struct inode *sufile, void *buf,
+				unsigned supsz, size_t nsup)
+{
+	struct buffer_head *bh;
+	struct nilfs_suinfo_update *sup, *supv = buf;
+	struct nilfs_segment_usage *su;
+	void *kaddr;
+	unsigned long blkoff, prev_blkoff;
+	size_t nerr = 0;
+	int ret = 0;
+
+	if (unlikely(nsup == 0))
+		goto out;
+
+	down_write(&NILFS_MDT(sufile)->mi_sem);
+	for (sup = supv; sup < supv + nsup; sup++) {
+		if (unlikely(sup->sup_segnum >=
+				nilfs_sufile_get_nsegments(sufile))) {

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 918

Quoted 10 lines
fs/nilfs2/sufile.c +10 -0
+			printk(KERN_WARNING
+			       "%s: invalid segment number: %llu\n", __func__,
+			       (unsigned long long)sup->sup_segnum);
+			nerr++;
+		}
+	}
+	if (nerr > 0) {
+		ret = -EINVAL;
+		goto out_sem;
+	}

Seems that you can exit from inside the loop:

Quoted 9 lines
Quoted 9 lines
	for (sup = supv; sup < supv + nsup; sup++) {
		if (unlikely(sup->sup_segnum >=
				nilfs_sufile_get_nsegments(sufile))) {
			printk(KERN_WARNING
			       "%s: invalid segment number: %llu\n", __func__,
			       (unsigned long long)sup->sup_segnum);
			ret = -EINVAL;
			goto out_sem;
		}

An additional comment:

I think we should reject unknown sup_flags with -EINVAL here. It may be used in a future version, but the current version cannot update the corresponding field in sufile. Rejecting it looks better behavior than ignoring it.

Regards,
Ryusuke Konishi

Quoted 88 lines
Quoted 1 line
	}

Yes. I copied that from nilfs_sufile_updatev.

Quoted 25 lines
Quoted 10 lines
fs/nilfs2/sufile.c +10 -0
+
+	sup = supv;
+	blkoff = nilfs_sufile_get_blkoff(sufile, sup->sup_segnum);
+	ret = nilfs_mdt_get_block(sufile, blkoff, 1, NULL, &bh);
+	if (ret < 0)
+		goto out_sem;
+
+	for (;;) {
+		kaddr = kmap_atomic(bh->b_page);
+		su = nilfs_sufile_block_get_segment_usage(

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 938

Quoted 10 lines
fs/nilfs2/sufile.c +10 -0
+			sufile, sup->sup_segnum, bh, kaddr);
+
+		if (nilfs_suinfo_update_lastmod(sup))
+			su->su_lastmod = cpu_to_le64(sup->sup_sui.sui_lastmod);
+
+		if (nilfs_suinfo_update_nblocks(sup))
+			su->su_nblocks = cpu_to_le32(sup->sup_sui.sui_nblocks);
+
+		if (nilfs_suinfo_update_flags(sup))
+			su->su_flags = cpu_to_le32(sup->sup_sui.sui_flags);

You must also update the counter value of sh_ncleansegs, sh_ndirtysegs in the nilfs_sufile_header struct of sufile header block based on the change of these flags.

Quoted 5 lines

In addition, you should ignore NILFS_SEGMENT_USAGE_ACTIVE_FLAG as below because this flag is a virtual flag set by running nilfs kernel code. The flag bit should not be written to sufile on disk.

          (sui_flags & ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE))

Yes. I didn't think of that.

Quoted 9 lines

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 942

Quoted 4 lines
fs/nilfs2/sufile.c +4 -0
+
+		kunmap_atomic(kaddr);
+
+		if (++sup >= supv + nsup)

You must not use the automatic pointer operation of C language for nilfs_suinfo_update because it may be extended in a future release. This "++sup" breaks forward compatibility of the ioctl.

Quoted 6 lines

You should do this by:

                sup = (void *)sup + supsz;

Note that pointer type is automatically converted for "void *" type variables.

Makes sense. I guess I blindly copied that from nilfs_sufile_updatev, but with a simple array of __u64 it works of course. With a structure, that is subject to change, not so much any more.

Quoted 22 lines

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 949

Quoted 7 lines
fs/nilfs2/sufile.c +7 -0
+			break;
+		prev_blkoff = blkoff;
+		blkoff = nilfs_sufile_get_blkoff(sufile, sup->sup_segnum);
+		if (blkoff == prev_blkoff)
+			continue;
+
+		/* get different block */

You must mark bh that this function changed as dirty with mark_buffer_dirty(bh). Otherwise, the change will be gone.

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 956

Quoted 7 lines
fs/nilfs2/sufile.c +7 -0
+		brelse(bh);
+		ret = nilfs_mdt_get_block(sufile, blkoff, 1, NULL, &bh);
+		if (unlikely(ret < 0))
+			goto out_sem;
+	}
+	brelse(bh);
+

The sufile should be marked as dirty (if any change happened):

Quoted 1 line
    nilfs_mdt_mark_dirty(sufile);

Of course. I am sorry that's a really stupid error. I will fix it right away.

Thanks for your review. I am really embarrassed about all the stupid avoidable errors.

Quoted 6 lines

br,
Andreas Rohner
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#43 lore raw

PATCH v2 3/3 nilfs2: implementation of NILFS_IOCTL_SET_SUINFO ioctl

In reply to a message not in the archive

With this ioctl the segment usage information in the SUFILE can be updated from userspace.

This is useful, because it allows the userspace GC to modify and update segment usage entries for specific segments, which enables it to avoid unnecessary write operations.

If a segment needs to be cleaned, but there is no or very little free space to be gained, the cleaning operation basically degrades to needless expensive copying of data. In the end the only thing that changes is the location of the data and a timestamp in the segment usage info. With this ioctl the GC can skip the copying and update the segment usage entries directly instead.

---
 fs/nilfs2/ioctl.c         | 50 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/nilfs2_fs.h |  2 ++
 2 files changed, 52 insertions(+)
fs/nilfs2/ioctl.c +50 -0
index b44bdb2..c6a3faf 100644
@@ -273,6 +273,13 @@ nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
 	return ret;
 }
 
+static ssize_t
+nilfs_ioctl_do_set_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
+			  void *buf, size_t size, size_t nmembs)
+{
+	return nilfs_sufile_set_suinfo(nilfs->ns_sufile, buf, size, nmembs);
+}
+
 static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp,
 				  unsigned int cmd, void __user *argp)
 {
@@ -767,6 +774,44 @@ out:
 	return ret;
 }
 
+static int nilfs_ioctl_set_info(struct inode *inode, struct file *filp,
+				unsigned int cmd, void __user *argp,
+				size_t membsz,
+				ssize_t (*dofunc)(struct the_nilfs *,
+						  __u64 *, int,
+						  void *, size_t, size_t))
+{
+	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
+	struct nilfs_transaction_info ti;
+	struct nilfs_argv argv;
+	int ret;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	ret = mnt_want_write_file(filp);
+	if (ret)
+		return ret;
+
+	ret = -EFAULT;
+	if (copy_from_user(&argv, argp, sizeof(argv)))
+		goto out;
+
+	if (argv.v_size < membsz)
+		return -EINVAL;
+
+	nilfs_transaction_begin(inode->i_sb, &ti, 0);
+	ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc);
+	if (unlikely(ret < 0))
+		nilfs_transaction_abort(inode->i_sb);
+	else
+		nilfs_transaction_commit(inode->i_sb); /* never fails */
+
+out:
+	mnt_drop_write_file(filp);
+	return ret;
+}
+
 static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp,
 				unsigned int cmd, void __user *argp,
 				size_t membsz,
@@ -820,6 +865,10 @@ long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 		return nilfs_ioctl_get_info(inode, filp, cmd, argp,
 					    sizeof(struct nilfs_suinfo),
 					    nilfs_ioctl_do_get_suinfo);
+	case NILFS_IOCTL_SET_SUINFO:
+		return nilfs_ioctl_set_info(inode, filp, cmd, argp,
+					    sizeof(struct nilfs_suinfo_update),
+					    nilfs_ioctl_do_set_suinfo);
 	case NILFS_IOCTL_GET_SUSTAT:
 		return nilfs_ioctl_get_sustat(inode, filp, cmd, argp);
 	case NILFS_IOCTL_GET_VINFO:
@@ -859,6 +908,7 @@ long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 	case NILFS_IOCTL_GET_CPINFO:
 	case NILFS_IOCTL_GET_CPSTAT:
 	case NILFS_IOCTL_GET_SUINFO:
+	case NILFS_IOCTL_SET_SUINFO:
 	case NILFS_IOCTL_GET_SUSTAT:
 	case NILFS_IOCTL_GET_VINFO:
 	case NILFS_IOCTL_GET_BDESCS:
include/linux/nilfs2_fs.h +2 -0
index 2ee1594..528e2c5 100644
@@ -902,5 +902,7 @@ struct nilfs_bdesc {
 	_IOW(NILFS_IOCTL_IDENT, 0x8B, __u64)
 #define NILFS_IOCTL_SET_ALLOC_RANGE  \
 	_IOW(NILFS_IOCTL_IDENT, 0x8C, __u64[2])
+#define NILFS_IOCTL_SET_SUINFO  \
+	_IOW(NILFS_IOCTL_IDENT, 0x8D, struct nilfs_argv)
 
 #endif	/* _LINUX_NILFS_FS_H */
Signature · 6 lines
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 6fb5a6d45afca9ae2599c471c0e42805ed1b6c55.1390312777.git.andreas.rohner-hi6Y0CQ0nG0@public.gmane.org

#45 lore raw

Re: [PATCH v2 3/3] nilfs2: implementation of NILFS_IOCTL_SET_SUINFO ioctl

Quoted 60 lines · Andreas Rohner

With this ioctl the segment usage information in the SUFILE can be updated from userspace.

This is useful, because it allows the userspace GC to modify and update segment usage entries for specific segments, which enables it to avoid unnecessary write operations.

If a segment needs to be cleaned, but there is no or very little free space to be gained, the cleaning operation basically degrades to needless expensive copying of data. In the end the only thing that changes is the location of the data and a timestamp in the segment usage info. With this ioctl the GC can skip the copying and update the segment usage entries directly instead.

---
 fs/nilfs2/ioctl.c         | 50 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/nilfs2_fs.h |  2 ++
 2 files changed, 52 insertions(+)
fs/nilfs2/ioctl.c +25 -0
index b44bdb2..c6a3faf 100644
@@ -273,6 +273,13 @@ nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
 	return ret;
 }
 
+static ssize_t
+nilfs_ioctl_do_set_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
+			  void *buf, size_t size, size_t nmembs)
+{
+	return nilfs_sufile_set_suinfo(nilfs->ns_sufile, buf, size, nmembs);
+}
+
 static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp,
 				  unsigned int cmd, void __user *argp)
 {
@@ -767,6 +774,44 @@ out:
 	return ret;
 }
 
+static int nilfs_ioctl_set_info(struct inode *inode, struct file *filp,
+				unsigned int cmd, void __user *argp,
+				size_t membsz,
+				ssize_t (*dofunc)(struct the_nilfs *,
+						  __u64 *, int,
+						  void *, size_t, size_t))
+{
+	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
+	struct nilfs_transaction_info ti;
+	struct nilfs_argv argv;
+	int ret;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	ret = mnt_want_write_file(filp);
+	if (ret)
+		return ret;

fs/nilfs2/ioctl.c out: · line 804

Quoted 10 lines
fs/nilfs2/ioctl.c +10 -0
+
+	ret = -EFAULT;
+	if (copy_from_user(&argv, argp, sizeof(argv)))
+		goto out;
+
+	if (argv.v_size < membsz)
+		return -EINVAL;
+
+	nilfs_transaction_begin(inode->i_sb, &ti, 0);
+	ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc);

Hmm, we have a problem here.

nilfs_ioctl_wrap_copy() cannot be used between nilfs_transcation_begin() and nilfs_transaction_end() since nilfs_ioctl_wrap_copy() calls copy_from_user() and/or copy_to_user(). Unfortunately there is a lock order restriction for these functions.

Let's use vmalloc() like nilfs_ioctl_clean_segments(). The following is a sample code for this:

	size_t len;
	void __user *base;
	void *kbuf;
	int ret;

	...
	ret = -EINVAL;
	if (argv.v_size < sizeof(struct nilfs_suinfo_update))
		goto out;

	< range check of argv.v_nmembs >

	len = argv.v_size * argv.v_nmembs;
	base = (void __user *)(unsigned long)argv.v_base;
	kbuf = vmalloc(len);
	if (!kbuf) {
		ret = -ENOMEM;
		goto out;
	}

	if (copy_from_user(kbuf, base, len)) {
		ret = -EFAULT;
		goto out_free;
	}

	nilfs_transaction_begin(inode->i_sb, &ti, 0);
	ret = < call nilfs_sufile_set_suinfo > ;
	if (unlikely(ret < 0))
		nilfs_transcation_abort(inode->i_sb);
	else
		nilfs_transcation_commit(inode->i_sb);

out_free:

	vfree(kbuf);
out:
	mnt_drop_write_file(filp);
	...

Thanks,
Ryusuke Konishi

Quoted 51 lines
fs/nilfs2/ioctl.c +15 -0
+	if (unlikely(ret < 0))
+		nilfs_transaction_abort(inode->i_sb);
+	else
+		nilfs_transaction_commit(inode->i_sb); /* never fails */
+
+out:
+	mnt_drop_write_file(filp);
+	return ret;
+}
+
 static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp,
 				unsigned int cmd, void __user *argp,
 				size_t membsz,
@@ -820,6 +865,10 @@ long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 		return nilfs_ioctl_get_info(inode, filp, cmd, argp,
 					    sizeof(struct nilfs_suinfo),
 					    nilfs_ioctl_do_get_suinfo);
+	case NILFS_IOCTL_SET_SUINFO:
+		return nilfs_ioctl_set_info(inode, filp, cmd, argp,
+					    sizeof(struct nilfs_suinfo_update),
+					    nilfs_ioctl_do_set_suinfo);
 	case NILFS_IOCTL_GET_SUSTAT:
 		return nilfs_ioctl_get_sustat(inode, filp, cmd, argp);
 	case NILFS_IOCTL_GET_VINFO:
@@ -859,6 +908,7 @@ long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 	case NILFS_IOCTL_GET_CPINFO:
 	case NILFS_IOCTL_GET_CPSTAT:
 	case NILFS_IOCTL_GET_SUINFO:
+	case NILFS_IOCTL_SET_SUINFO:
 	case NILFS_IOCTL_GET_SUSTAT:
 	case NILFS_IOCTL_GET_VINFO:
 	case NILFS_IOCTL_GET_BDESCS:
include/linux/nilfs2_fs.h +2 -0
index 2ee1594..528e2c5 100644
@@ -902,5 +902,7 @@ struct nilfs_bdesc {
 	_IOW(NILFS_IOCTL_IDENT, 0x8B, __u64)
 #define NILFS_IOCTL_SET_ALLOC_RANGE  \
 	_IOW(NILFS_IOCTL_IDENT, 0x8C, __u64[2])
+#define NILFS_IOCTL_SET_SUINFO  \
+	_IOW(NILFS_IOCTL_IDENT, 0x8D, struct nilfs_argv)
 
 #endif	/* _LINUX_NILFS_FS_H */
Signature · 6 lines
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 20140124.222016.110509397.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org

#47 lore raw

Re: [PATCH v2 3/3] nilfs2: implementation of NILFS_IOCTL_SET_SUINFO ioctl

Quoted 114 lines · Ryusuke Konishi
Quoted 60 lines · Andreas Rohner

With this ioctl the segment usage information in the SUFILE can be updated from userspace.

This is useful, because it allows the userspace GC to modify and update segment usage entries for specific segments, which enables it to avoid unnecessary write operations.

If a segment needs to be cleaned, but there is no or very little free space to be gained, the cleaning operation basically degrades to needless expensive copying of data. In the end the only thing that changes is the location of the data and a timestamp in the segment usage info. With this ioctl the GC can skip the copying and update the segment usage entries directly instead.

---
 fs/nilfs2/ioctl.c         | 50 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/nilfs2_fs.h |  2 ++
 2 files changed, 52 insertions(+)
fs/nilfs2/ioctl.c +25 -0
index b44bdb2..c6a3faf 100644
@@ -273,6 +273,13 @@ nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
 	return ret;
 }
 
+static ssize_t
+nilfs_ioctl_do_set_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
+			  void *buf, size_t size, size_t nmembs)
+{
+	return nilfs_sufile_set_suinfo(nilfs->ns_sufile, buf, size, nmembs);
+}
+
 static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp,
 				  unsigned int cmd, void __user *argp)
 {
@@ -767,6 +774,44 @@ out:
 	return ret;
 }
 
+static int nilfs_ioctl_set_info(struct inode *inode, struct file *filp,
+				unsigned int cmd, void __user *argp,
+				size_t membsz,
+				ssize_t (*dofunc)(struct the_nilfs *,
+						  __u64 *, int,
+						  void *, size_t, size_t))
+{
+	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
+	struct nilfs_transaction_info ti;
+	struct nilfs_argv argv;
+	int ret;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	ret = mnt_want_write_file(filp);
+	if (ret)
+		return ret;

fs/nilfs2/ioctl.c out: · line 804

Quoted 10 lines
fs/nilfs2/ioctl.c +10 -0
+
+	ret = -EFAULT;
+	if (copy_from_user(&argv, argp, sizeof(argv)))
+		goto out;
+
+	if (argv.v_size < membsz)
+		return -EINVAL;
+
+	nilfs_transaction_begin(inode->i_sb, &ti, 0);
+	ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc);

Hmm, we have a problem here.

nilfs_ioctl_wrap_copy() cannot be used between nilfs_transcation_begin() and nilfs_transaction_end() since nilfs_ioctl_wrap_copy() calls copy_from_user() and/or copy_to_user(). Unfortunately there is a lock order restriction for these functions.

Let's use vmalloc() like nilfs_ioctl_clean_segments(). The following is a sample code for this:

	size_t len;
	void __user *base;
	void *kbuf;
	int ret;

	...
	ret = -EINVAL;
	if (argv.v_size < sizeof(struct nilfs_suinfo_update))
		goto out;

	< range check of argv.v_nmembs >

	len = argv.v_size * argv.v_nmembs;
	base = (void __user *)(unsigned long)argv.v_base;
	kbuf = vmalloc(len);
	if (!kbuf) {
		ret = -ENOMEM;
		goto out;
	}

	if (copy_from_user(kbuf, base, len)) {
		ret = -EFAULT;
		goto out_free;
	}

	nilfs_transaction_begin(inode->i_sb, &ti, 0);
	ret = < call nilfs_sufile_set_suinfo > ;
	if (unlikely(ret < 0))
		nilfs_transcation_abort(inode->i_sb);
	else
		nilfs_transcation_commit(inode->i_sb);
Quoted 6 lines

out_free:

	vfree(kbuf);
out:
	mnt_drop_write_file(filp);
	...

Then we don't need the ugly nilfs_suinfo_update structure. I can just send an array of struct nilfs_argv[2]. First element has the segment numbers and second element has the nilfs_suinfo structures and flags are in v_flags. Would that be acceptable?

br,
Andreas Rohner
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): [email protected]

#49 lore raw

Re: [PATCH v2 3/3] nilfs2: implementation of NILFS_IOCTL_SET_SUINFO ioctl

Quoted 122 lines · Andreas Rohner
Quoted 114 lines · Ryusuke Konishi
Quoted 60 lines · Andreas Rohner

With this ioctl the segment usage information in the SUFILE can be updated from userspace.

This is useful, because it allows the userspace GC to modify and update segment usage entries for specific segments, which enables it to avoid unnecessary write operations.

If a segment needs to be cleaned, but there is no or very little free space to be gained, the cleaning operation basically degrades to needless expensive copying of data. In the end the only thing that changes is the location of the data and a timestamp in the segment usage info. With this ioctl the GC can skip the copying and update the segment usage entries directly instead.

---
 fs/nilfs2/ioctl.c         | 50 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/nilfs2_fs.h |  2 ++
 2 files changed, 52 insertions(+)
fs/nilfs2/ioctl.c +25 -0
index b44bdb2..c6a3faf 100644
@@ -273,6 +273,13 @@ nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
 	return ret;
 }
 
+static ssize_t
+nilfs_ioctl_do_set_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
+			  void *buf, size_t size, size_t nmembs)
+{
+	return nilfs_sufile_set_suinfo(nilfs->ns_sufile, buf, size, nmembs);
+}
+
 static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp,
 				  unsigned int cmd, void __user *argp)
 {
@@ -767,6 +774,44 @@ out:
 	return ret;
 }
 
+static int nilfs_ioctl_set_info(struct inode *inode, struct file *filp,
+				unsigned int cmd, void __user *argp,
+				size_t membsz,
+				ssize_t (*dofunc)(struct the_nilfs *,
+						  __u64 *, int,
+						  void *, size_t, size_t))
+{
+	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
+	struct nilfs_transaction_info ti;
+	struct nilfs_argv argv;
+	int ret;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	ret = mnt_want_write_file(filp);
+	if (ret)
+		return ret;

fs/nilfs2/ioctl.c out: · line 804

Quoted 10 lines
fs/nilfs2/ioctl.c +10 -0
+
+	ret = -EFAULT;
+	if (copy_from_user(&argv, argp, sizeof(argv)))
+		goto out;
+
+	if (argv.v_size < membsz)
+		return -EINVAL;
+
+	nilfs_transaction_begin(inode->i_sb, &ti, 0);
+	ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc);

Hmm, we have a problem here.

nilfs_ioctl_wrap_copy() cannot be used between nilfs_transcation_begin() and nilfs_transaction_end() since nilfs_ioctl_wrap_copy() calls copy_from_user() and/or copy_to_user(). Unfortunately there is a lock order restriction for these functions.

Let's use vmalloc() like nilfs_ioctl_clean_segments(). The following is a sample code for this:

	size_t len;
	void __user *base;
	void *kbuf;
	int ret;

	...
	ret = -EINVAL;
	if (argv.v_size < sizeof(struct nilfs_suinfo_update))
		goto out;

	< range check of argv.v_nmembs >

	len = argv.v_size * argv.v_nmembs;
	base = (void __user *)(unsigned long)argv.v_base;
	kbuf = vmalloc(len);
	if (!kbuf) {
		ret = -ENOMEM;
		goto out;
	}

	if (copy_from_user(kbuf, base, len)) {
		ret = -EFAULT;
		goto out_free;
	}

	nilfs_transaction_begin(inode->i_sb, &ti, 0);
	ret = < call nilfs_sufile_set_suinfo > ;
	if (unlikely(ret < 0))
		nilfs_transcation_abort(inode->i_sb);
	else
		nilfs_transcation_commit(inode->i_sb);
Quoted 6 lines

out_free:

	vfree(kbuf);
out:
	mnt_drop_write_file(filp);
	...
Quoted 4 lines

Then we don't need the ugly nilfs_suinfo_update structure. I can just send an array of struct nilfs_argv[2]. First element has the segment numbers and second element has the nilfs_suinfo structures and flags are in v_flags. Would that be acceptable?

Personally, I don't like nilfs_argv[n]. Unfortunately, we couldn't find a good way to pass several array arguments together for GC.

For NILFS_IOCTL_SET_SUINFO, using nilfs_suinfo_update struct looks better to me from the viewpoint of memory access locality and readability (and clarity) of source code.

Regards,
Ryusuke Konishi

Quoted 6 lines

br,
Andreas Rohner
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#50 lore raw

Re: [PATCH v2 1/3] nilfs2: add new nilfs_suinfo_update struct

In reply to a message not in the archive
Quoted 21 lines · Andreas Rohner

This adds struct nilfs_suinfo_update and some flags. It contains the information needed to update one entry of segment usage information in the SUFILE. The flags specify, which fields need to be updated.

This can be used to update segment usage information from userspace with an ioctl.

---
 include/linux/nilfs2_fs.h | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)
include/linux/nilfs2_fs.h +1 -0
index 9875576..2ee1594 100644
@@ -709,6 +709,45 @@ static inline int nilfs_suinfo_clean(const struct nilfs_suinfo *si)
 	return !si->sui_flags;
 }
 
+/**

include/linux/nilfs2_fs.h static inline int nilfs_suinfo_clean(const struct nilfs_suinfo *si) · line 722

Quoted 10 lines
include/linux/nilfs2_fs.h +10 -0
+ * nilfs_suinfo_update - segment usage information update
+ * @sup_segnum: segment number
+ * @sup_flags: flags for which fields are active in sup_sui
+ * @sup_sui: segment usage information
+ */
+struct nilfs_suinfo_update {
+	__u64 sup_segnum;
+	__u32 sup_flags;
+	struct nilfs_suinfo sup_sui;
+};

This structure is not aligned on 8 byte boundary. You need a 4 byte pad to make the alignment architecture independent since the structure already has some 64-bit variables.

If you do not so, the ioctl will lose compatibility, for instance, between 32 bit userland programs and 64 bit kernel.

struct nilfs_suinfo_update {
	__u64 sup_segnum;
	__u32 sup_flags;
	__u32 sup_reserved;
	struct nilfs_suinfo sup_sui;
};

Do you really need different suinfo update flags per segment ?

If it's not so, we don't have to add nilfs_suinfo_update structure. v_flags of nilfs_argv structure looks to be available for that purpose. It's just a confirmation. Basically, I think this extension is acceptable.

Regards,
Ryusuke Konishi

Quoted 38 lines
include/linux/nilfs2_fs.h +28 -0
+
+enum {
+	NILFS_SUINFO_UPDATE_LASTMOD,
+	NILFS_SUINFO_UPDATE_NBLOCKS,
+	NILFS_SUINFO_UPDATE_FLAGS,
+};
+
+#define NILFS_SUINFO_UPDATE_FNS(flag, name)				\
+static inline void							\
+nilfs_suinfo_update_set_##name(struct nilfs_suinfo_update *sup)		\
+{									\
+	sup->sup_flags |= 1UL << NILFS_SUINFO_UPDATE_##flag;		\
+}									\
+static inline void							\
+nilfs_suinfo_update_clear_##name(struct nilfs_suinfo_update *sup)	\
+{									\
+	sup->sup_flags &= ~(1UL << NILFS_SUINFO_UPDATE_##flag);		\
+}									\
+static inline int							\
+nilfs_suinfo_update_##name(const struct nilfs_suinfo_update *sup)	\
+{									\
+	return !!(sup->sup_flags & (1UL << NILFS_SUINFO_UPDATE_##flag));\
+}
+
+NILFS_SUINFO_UPDATE_FNS(LASTMOD, lastmod)
+NILFS_SUINFO_UPDATE_FNS(NBLOCKS, nblocks)
+NILFS_SUINFO_UPDATE_FNS(FLAGS, flags)
+
 /* ioctl */
 enum {
 	NILFS_CHECKPOINT,
Signature · 6 lines
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 20140124.135635.27780504.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org

#52 lore raw

Re: [PATCH v2 1/3] nilfs2: add new nilfs_suinfo_update struct

Quoted 40 lines · Ryusuke Konishi
Quoted 21 lines · Andreas Rohner

This adds struct nilfs_suinfo_update and some flags. It contains the information needed to update one entry of segment usage information in the SUFILE. The flags specify, which fields need to be updated.

This can be used to update segment usage information from userspace with an ioctl.

---
 include/linux/nilfs2_fs.h | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)
include/linux/nilfs2_fs.h +1 -0
index 9875576..2ee1594 100644
@@ -709,6 +709,45 @@ static inline int nilfs_suinfo_clean(const struct nilfs_suinfo *si)
 	return !si->sui_flags;
 }
 
+/**

include/linux/nilfs2_fs.h static inline int nilfs_suinfo_clean(const struct nilfs_suinfo *si) · line 722

Quoted 10 lines
include/linux/nilfs2_fs.h +10 -0
+ * nilfs_suinfo_update - segment usage information update
+ * @sup_segnum: segment number
+ * @sup_flags: flags for which fields are active in sup_sui
+ * @sup_sui: segment usage information
+ */
+struct nilfs_suinfo_update {
+	__u64 sup_segnum;
+	__u32 sup_flags;
+	struct nilfs_suinfo sup_sui;
+};

This structure is not aligned on 8 byte boundary. You need a 4 byte pad to make the alignment architecture independent since the structure already has some 64-bit variables.

If you do not so, the ioctl will lose compatibility, for instance, between 32 bit userland programs and 64 bit kernel.

Quoted 6 lines
struct nilfs_suinfo_update {
	__u64 sup_segnum;
	__u32 sup_flags;
	__u32 sup_reserved;
	struct nilfs_suinfo sup_sui;
};

Ok, I thought 4 byte alignment would be enough. But now I see the problem, nilfs_suinfo contains 64 bit values, that need to be 8 byte aligned on a 64 bit architecture.

Quoted 1 line

Do you really need different suinfo update flags per segment ?

No.

Quoted 2 lines

If it's not so, we don't have to add nilfs_suinfo_update structure. v_flags of nilfs_argv structure looks to be available for that purpose.

Yes v_flags is available, but I need nilfs_suinfo_update to contain the segment number. I can't use v_index for the segment number like with GET_SUINFO, because the segment numbers are not necessarily sequential. If I use v_index I could effectively only use the ioctl to update one segment at a time. So I thought, since I need nilfs_suinfo_update anyway, I might as well put the flags there. But with the extra alignment it gets a bit ugly, so I tend to agree with you to put the flags into v_flags now.

Maybe I missed something, but how would you propose to send the segment numbers, only using nilfs_suinfo and nilfs_argv?

It is certainly possible to use v_index of nilfs_argv and update one segment at a time. It shouldn't be a problem, because there are at most

#define NILFS_CLDCONFIG_NSEGMENTS_PER_CLEAN_MAX 32

segments to be updated.

Quoted 2 lines

It's just a confirmation. Basically, I think this extension is acceptable.

Cool. Thanks!

br,
Andreas Rohner
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): [email protected]

#54 lore raw

Re: [PATCH v2 1/3] nilfs2: add new nilfs_suinfo_update struct

Quoted 4 lines · Andreas Rohner
Quoted 2 lines · Ryusuke Konishi

On Tue, 21 Jan 2014 15:00:28 +0100, Andreas Rohner wrote:
Do you really need different suinfo update flags per segment ?

Quoted 8 lines

No.

Quoted 2 lines

If it's not so, we don't have to add nilfs_suinfo_update structure. v_flags of nilfs_argv structure looks to be available for that purpose.

Yes v_flags is available, but I need nilfs_suinfo_update to contain the segment number. I can't use v_index for the segment number like with GET_SUINFO, because the segment numbers are not necessarily sequential.

Ok, it sounds reasonable. Please go ahead.

Ryusuke Konishi

Quoted 19 lines

If I use v_index I could effectively only use the ioctl to update one segment at a time. So I thought, since I need nilfs_suinfo_update anyway, I might as well put the flags there. But with the extra alignment it gets a bit ugly, so I tend to agree with you to put the flags into v_flags now.

Maybe I missed something, but how would you propose to send the segment numbers, only using nilfs_suinfo and nilfs_argv?

It is certainly possible to use v_index of nilfs_argv and update one segment at a time. It shouldn't be a problem, because there are at most

#define NILFS_CLDCONFIG_NSEGMENTS_PER_CLEAN_MAX 32

segments to be updated.

Quoted 2 lines

It's just a confirmation. Basically, I think this extension is acceptable.

Quoted 8 lines

Cool. Thanks!

br,
Andreas Rohner
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#55 lore raw
In reply to a message not in the archive
Quoted 14 lines · Andreas Rohner

Hi,

This is the second version of this patch set. It replaces the kind of hacky use of v_flags with a proper implementation of NILFS_IOCTL_SET_SUINFO ioctl.

v1->v2
* Implementation of NILFS_IOCTL_SET_SUINFO
* Added mc_min_free_blocks_threshold config option (if clean segments < min_clean_segments)
* Added new command line param for nilfs-clean
* Update man- and config-files
* Simpler benchmark

Quoted 6 lines

This patch set implements a small new feature and there shouldn't be any compatibility issues. It enables the GC to check how much free space can be gained from cleaning a segment and if it is less than a certain threshold it will abort the operation and try a different segment. Although no blocks need to be moved, the SUFILE entry of the corresponding segment needs to be updated to avoid an infinite loop.

As a user (not a NILFS2 developer), I'll have to live with this one for a while to see how well I like it. On x86, xfstests went well for my debug DEBUG_PAGEALLOC CONFIG_AIO=n kernel 3.13.0+, no obvious before/after changes in speed, but no crashes, either. I hit a glitch with Vyacheslav's xattr/ACL pages on 2k blocksize filesystems, so I'll have to test smaller block sizes at a later time.

So that's your warning: small block sizes and POSIX AIO were not tested by me. If you don't have xfstests, get it. It's useful for finding bugs and regressions in filesystems.

Not having your super-secret test suite or disk space to run it, I went the other direction, using the commonly available fs_mark utility to make many tiny writes with 16 threads. My initial opinion is that your new GC code fixes some obvious lag when a filesystem is populated and nilfs_cleanerd starts to do its work. However, for reasons of code or simple mathematics, the file system hits end-of-space a bit earlier than does the unpatched code. I'll have to build some kernels, live with the system, and otherwise generate lots of checkpoints to know if this is a problem. IOW, I need to find out for myself if I need to make a slightly larger filesystem to do the same things using a patched NILFS2.

Thanks!

Michael

[sample collection of data from fs_mark below]

File/sec Output from this fs_mark command (two different runs)...

fs_mark -d /mnt/xfstests-test/test -F -D 16 -t 16 -n 150 -s 28672 -w 4096

...generates the following numbers for comparison:

FILES   OLD     NEW
2400    219.4   222.3
4800    210.5   217.9
7200    216.7   212
9600    216     213
12000   216.1   213.1
14400   215.5   213.4
16800   213.5   215.4
19200   212.5   214.9
21600   214.2   209.6
24000   212     200
26400   191.6   194.4
28800   211.3   208.6
31200   193.8   190.6
33600   188.2   174.6
36000   139.7   192.2
38400    78.9   204.9
40800   110.6   188.8
43200    73.8   205.9
45600    75.7   205.7
48000    76     190.4
50400   115.4   187
52800   180.8   190.6
55200   192.4   202
57600   158.3   206.8
60000   201.7   189.1
62400   174.8   200.7
64800   170     189.2
67200   203.3   187.7
69600   174.8   175
72000   150.9   174.3
74400   141.7   175.6
76800   199.5   174.6
79200   180.2   174.9
81600    66.8    77.1
84000    40.8    76.6
86400    67.3    86.9
88800    59.3    77.1
91200   127.1
93600   113.5
96000   110.1
98400   112.6
100800   75.5
103200   58
105600   53.8
108000   45.2
110400   45.9
112800   48.2

The test partition is a 4-GB MD RAID-0 partition, 64k chunk size, on old, damaged spinning rust HDDs and old x86 hardware. GC issues show up well when using small writes and small file sizes, at least on this hardware. If this test moves more quickly on your hardware (it should), try to increase the threads before increasing other parameters.

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): [email protected]

#57 lore raw

Hi Michael,

Quoted 5 lines · Michael L. Semon

Not having your super-secret test suite or disk space to run it, I went the other direction, using the commonly available fs_mark utility to make many tiny writes with 16 threads. My initial opinion is that your new GC code fixes some obvious lag when a filesystem is populated and nilfs_cleanerd starts to do its work.

Thanks for testing my code. It is not a super-secret test suite :), it's just a few 100 lines of crappy C code I am embarrassed to publish. Thanks for pointing out fs_mark, I didn't know it. From what I can see it seems to be the perfect tool to test the GC. I will repeat my measurements with fs_mark over the weekend.

Quoted 7 lines

However, for reasons of code
or simple mathematics, the file system hits end-of-space a bit earlier than does the unpatched code. I'll have to build some kernels, live with the system, and otherwise generate lots of checkpoints to know if this is a problem. IOW, I need to find out for myself if I need to make a slightly larger filesystem to do the same things using a patched NILFS2.

Maybe my default values are a bit too high. 256 blocks are about 1 MB with 4k blocks. So if you use the current default settings, you could potentially loose 1/8 of your free space.

By the way "blocks" is not a very good unit for the threshold in the config file anyway. If am thinking of changing it to "% of a segment", which would be independent of the block size and a lot more intuitive.

br,
Andreas Rohner
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): [email protected]

#59 lore raw
Quoted 9 lines · Andreas Rohner

Hi Michael,

Quoted 5 lines · Michael L. Semon

Not having your super-secret test suite or disk space to run it, I went the other direction, using the commonly available fs_mark utility to make many tiny writes with 16 threads. My initial opinion is that your new GC code fixes some obvious lag when a filesystem is populated and nilfs_cleanerd starts to do its work.

Quoted 5 lines

Thanks for testing my code. It is not a super-secret test suite :), it's just a few 100 lines of crappy C code I am embarrassed to publish. Thanks for pointing out fs_mark, I didn't know it. From what I can see it seems to be the perfect tool to test the GC. I will repeat my measurements with fs_mark over the weekend.

No problem, just making sure. I had some code to zero random bits on a partition, and I'll probably never post that in public, either. It's just hard to verify conclusions based on tools that I don't have.

fs_mark is one tool of many. That use of fs_mark came from trying to figure out RAID-0 stripe sizes; the NILFS2 results were by accident but reflect exactly what I'm seeing in prolonged normal use. xfstests has fsstress, fsx, and a few other special-purpose tools. There's also Flexible I/O Tester, but it's one of those cool scriptable testers that are a bit beyond my needs.

Quoted 11 lines
Quoted 7 lines

However, for reasons of code
or simple mathematics, the file system hits end-of-space a bit earlier than does the unpatched code. I'll have to build some kernels, live with the system, and otherwise generate lots of checkpoints to know if this is a problem. IOW, I need to find out for myself if I need to make a slightly larger filesystem to do the same things using a patched NILFS2.

Maybe my default values are a bit too high. 256 blocks are about 1 MB with 4k blocks. So if you use the current default settings, you could potentially loose 1/8 of your free space.

As long as I can plan free space in advance, all is well, though 12.5% is a little much. I try to plan NILFS2 to where I can run it all day without causing too much garbage collection, then run mkcp -s and nilfs-clean as cron jobs in the middle of the night.

Thanks!

Michael

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#60 lore raw
In reply to a message not in the archive
Quoted 6 lines · Andreas Rohner

Hi,

This is the second version of this patch set. It replaces the kind of hacky use of v_flags with a proper implementation of NILFS_IOCTL_SET_SUINFO ioctl.

Quoted 7 lines

v1->v2
* Implementation of NILFS_IOCTL_SET_SUINFO
* Added mc_min_free_blocks_threshold config option (if clean segments < min_clean_segments)
* Added new command line param for nilfs-clean
* Update man- and config-files
* Simpler benchmark

If you are talking about something then it should be in patchset. Otherwise, why do you mention about it?

Quoted 5 lines

This patch set implements a small new feature and there shouldn't be any compatibility issues. It enables the GC to check how much free space can be gained from cleaning a segment and if it is less than a certain threshold it will abort the operation and try a different segment.

When you have cleaned a segment then you can use the whole one. So, if segment has 8 MB in size then it will be available 8 MB free space. The phrase "It enables the GC to check how much free space can be gained from cleaning a segment" really confuses me. Because I always know how much space I gain after cleaning every segment. I suppose that you mean something different. Am I correct?

Quoted 5 lines

Although no blocks need to be moved, the SUFILE entry of the corresponding segment needs to be updated to avoid an infinite loop.

This is potentially useful for all gc policies, but it is especially beneficial for the timestamp policy.

I completely misunderstand this statement. What do you mean?

Quoted 11 lines

Lets assume for example a NILFS2
volume with 20% static files and lets assume these static files are in the oldest segments. The current timestamp policy will select the oldest segments and, since the data is static, move them mostly unchanged to new segments. After a while they will become the oldest segments again. Then timestamp will move them again. These moving operations are expensive and unnecessary.

I used a simple benchmark to test the patch set (only a few lines of C). I used a 100 GB partition and performed the following steps:

Quoted 7 lines

1. Write a 20 GB file
2. Write a 50 GB file
3. Overwrite chunks of 1 MB within the 50 GB file at random
4. Repeat step 3 until 60 GB of data is written

Steps 3 and 4 are only perfomed to get the GC started. So the benchmark writes a 130 GB in total to a 100 GB partition.

How is it possible to save 130 GB in 100 GB partition? Are you magician? :)

Quoted 19 lines

HHD:

   Timestamp GB Written: 340.7574
   Timestamp GB Read:    208.2935
   Timestamp Runtime:    7787.546s

   Patched GB Written:   313.2566
   Patched GB Read:      182.6389
   Patched Runtime:      7410.892s

SSD:

   Timestamp GB Written: 679.3901
   Timestamp GB Read:    242.59
   Timestamp Runtime:    3022.081s

   Patched GB Written:   500.0095
   Patched GB Read:      157.475   
   Patched Runtime:      2313.448
Quoted 7 lines

The results for the HDD clearly show, that about 20 GB less data has been written and read in the patched version. It is reasonable to assume, that these 20 GB are the static data.

The speed of the GC was tuned to the HDD. It was probably too aggressive for the much faster SSD. That is probably the reason why the difference in GB written and read is much higher than 20 GB.

I misunderstand completely what you mean here.

Thanks,
Vyacheslav Dubeyko.

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 85EBEC6B-CA69-472A-8DDD-8E056F809EC4-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org

#62 lore raw
Quoted 26 lines · Vyacheslav Dubeyko
Quoted 6 lines · Andreas Rohner

Hi,

This is the second version of this patch set. It replaces the kind of hacky use of v_flags with a proper implementation of NILFS_IOCTL_SET_SUINFO ioctl.

Quoted 7 lines

v1->v2
* Implementation of NILFS_IOCTL_SET_SUINFO
* Added mc_min_free_blocks_threshold config option (if clean segments < min_clean_segments)
* Added new command line param for nilfs-clean
* Update man- and config-files
* Simpler benchmark

If you are talking about something then it should be in patchset. Otherwise, why do you mention about it?

Quoted 5 lines

This patch set implements a small new feature and there shouldn't be any compatibility issues. It enables the GC to check how much free space can be gained from cleaning a segment and if it is less than a certain threshold it will abort the operation and try a different segment.

Quoted 6 lines

When you have cleaned a segment then you can use the whole one. So, if segment has 8 MB in size then it will be available 8 MB free space. The phrase "It enables the GC to check how much free space can be gained from cleaning a segment" really confuses me. Because I always know how much space I gain after cleaning every segment. I suppose that you mean something different. Am I correct?

You have to move the live blocks to a new segment, so you gain only (8 MB - live_blocks) of free space.

Quoted 7 lines
Quoted 5 lines

Although no blocks need to be moved, the SUFILE entry of the corresponding segment needs to be updated to avoid an infinite loop.

This is potentially useful for all gc policies, but it is especially beneficial for the timestamp policy.

I completely misunderstand this statement. What do you mean?

Well the timestamp policy always selects the oldest segment. If the oldest segment is below the threshold it won't be cleaned. If we don't change the timestamp it will be immediately selected again and it probably will still be below the threshold and so on in an infinite loop.

Quoted 16 lines
Quoted 16 lines

Lets assume for example a NILFS2
volume with 20% static files and lets assume these static files are in the oldest segments. The current timestamp policy will select the oldest segments and, since the data is static, move them mostly unchanged to new segments. After a while they will become the oldest segments again. Then timestamp will move them again. These moving operations are expensive and unnecessary.

I used a simple benchmark to test the patch set (only a few lines of C). I used a 100 GB partition and performed the following steps:

1. Write a 20 GB file
2. Write a 50 GB file
3. Overwrite chunks of 1 MB within the 50 GB file at random
4. Repeat step 3 until 60 GB of data is written

Quoted 4 lines
Quoted 2 lines

Steps 3 and 4 are only perfomed to get the GC started. So the benchmark writes a 130 GB in total to a 100 GB partition.

How is it possible to save 130 GB in 100 GB partition? Are you magician? :)

I OVERWRITE the 50 GB file. 130 GB is the total amount of data written to the partition.

Quoted 23 lines
Quoted 23 lines

HHD:

   Timestamp GB Written: 340.7574
   Timestamp GB Read:    208.2935
   Timestamp Runtime:    7787.546s

   Patched GB Written:   313.2566
   Patched GB Read:      182.6389
   Patched Runtime:      7410.892s

SSD:

   Timestamp GB Written: 679.3901
   Timestamp GB Read:    242.59
   Timestamp Runtime:    3022.081s

   Patched GB Written:   500.0095
   Patched GB Read:      157.475   
   Patched Runtime:      2313.448

The results for the HDD clearly show, that about 20 GB less data has been written and read in the patched version. It is reasonable to assume, that these 20 GB are the static data.

Quoted 5 lines
Quoted 3 lines

The speed of the GC was tuned to the HDD. It was probably too aggressive for the much faster SSD. That is probably the reason why the difference in GB written and read is much higher than 20 GB.

I misunderstand completely what you mean here.

You need to be a bit more specific. These are the results of my benchmark. The GB Written and GB Read values are calculated by simply importing /proc/diskstats into R (You subtract the values before the benchmark from those after the benchmark).

The patched version writes less and reads less. Pretty simple.

br,
Andreas Rohner

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): [email protected]

#64 lore raw
Quoted 16 lines

23 ÑÎ×. 2014 Ç., × 22:12, Andreas Rohner <[email protected]>:

Quoted 7 lines
Quoted 6 lines

This patch set implements a small new feature and there shouldn't be any compatibility issues. It enables the GC to check how much free space can be gained from cleaning a segment and if it is less than a certain threshold it will abort the operation and try a different segment.

Quoted 6 lines

When you have cleaned a segment then you can use the whole one. So, if segment has 8 MB in size then it will be available 8 MB free space. The phrase "It enables the GC to check how much free space can be gained from cleaning a segment" really confuses me. Because I always know how much space I gain after cleaning every segment. I suppose that you mean something different. Am I correct?

Quoted 2 lines

You have to move the live blocks to a new segment, so you gain only (8 MB - live_blocks) of free space.

You always will have 8 MB after cleaning (garbage collection). So, all segments are identical from the free space point of view. What does GC check? And how can GC distinguish segments on the basis of free space? All cleaned segments return 8 MB free space for further allocation. So, all used segments will be over any threshold.

Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

Although no blocks need to be moved, the SUFILE entry of the corresponding segment needs to be updated to avoid an infinite loop.

This is potentially useful for all gc policies, but it is especially beneficial for the timestamp policy.

Quoted 6 lines
Quoted 1 line

I completely misunderstand this statement. What do you mean?

Well the timestamp policy always selects the oldest segment. If the oldest segment is below the threshold it won't be cleaned. If we don't change the timestamp it will be immediately selected again and it probably will still be below the threshold and so on in an infinite loop.

I understand your approach. But I misunderstand about what usefulness you are talking. What is it?

[snip]

Quoted 5 lines
Quoted 5 lines
Quoted 4 lines

The speed of the GC was tuned to the HDD. It was probably too aggressive for the much faster SSD. That is probably the reason why the difference in GB written and read is much higher than 20 GB.

Quoted 8 lines
Quoted 1 line

I misunderstand completely what you mean here.

You need to be a bit more specific. These are the results of my benchmark. The GB Written and GB Read values are calculated by simply importing /proc/diskstats into R (You subtract the values before the benchmark from those after the benchmark).

The patched version writes less and reads less. Pretty simple.

Here I asked about aggressiveness related to SSD. What do you mean?

Thanks,
Vyacheslav Dubeyko.

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): FC7F25C5-1E72-4DF5-B860-FBCE36E91EAB-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org

#66 lore raw
Quoted 16 lines · Vyacheslav Dubeyko
Quoted 16 lines

23 янв. 2014 г., в 22:12, Andreas Rohner <[email protected]>:

Quoted 13 lines
Quoted 6 lines

This patch set implements a small new feature and there shouldn't be any compatibility issues. It enables the GC to check how much free space can be gained from cleaning a segment and if it is less than a certain threshold it will abort the operation and try a different segment.

When you have cleaned a segment then you can use the whole one. So, if segment has 8 MB in size then it will be available 8 MB free space. The phrase "It enables the GC to check how much free space can be gained from cleaning a segment" really confuses me. Because I always know how much space I gain after cleaning every segment. I suppose that you mean something different. Am I correct?

Quoted 8 lines
Quoted 2 lines

You have to move the live blocks to a new segment, so you gain only (8 MB - live_blocks) of free space.

You always will have 8 MB after cleaning (garbage collection). So, all segments are identical from the free space point of view. What does GC check? And how can GC distinguish segments on the basis of free space? All cleaned segments return 8 MB free space for further allocation. So, all used segments will be over any threshold.

I am sorry if I wasn't clear enough. The invalidated blocks in a segment are basically unusable free space, that needs to be garbage collected. If you clean a segment you only gain the space of the invalidated blocks, from the perspective of the whole file system. Of course the whole segment is free after cleaning, but the live blocks were moved somewhere else and occupy space there. So from the perspective of the whole file system you only really gained the amount of space occupied by the invalidated blocks.

Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
Quoted 5 lines

Although no blocks need to be moved, the SUFILE entry of the corresponding segment needs to be updated to avoid an infinite loop.

This is potentially useful for all gc policies, but it is especially beneficial for the timestamp policy.

I completely misunderstand this statement. What do you mean?

Quoted 8 lines
Quoted 4 lines

Well the timestamp policy always selects the oldest segment. If the oldest segment is below the threshold it won't be cleaned. If we don't change the timestamp it will be immediately selected again and it probably will still be below the threshold and so on in an infinite loop.

I understand your approach. But I misunderstand about what usefulness you are talking. What is it?

It helps to avoid unnecessary copy operations of data.

Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
Quoted 4 lines

The speed of the GC was tuned to the HDD. It was probably too aggressive for the much faster SSD. That is probably the reason why the difference in GB written and read is much higher than 20 GB.

I misunderstand completely what you mean here.

Quoted 8 lines
Quoted 6 lines

You need to be a bit more specific. These are the results of my benchmark. The GB Written and GB Read values are calculated by simply importing /proc/diskstats into R (You subtract the values before the benchmark from those after the benchmark).

The patched version writes less and reads less. Pretty simple.

Here I asked about aggressiveness related to SSD. What do you mean?

I meant the configuration of the GC. The benchmark writes a lot of data, and the GC needs to keep up with that. So I configured

protection_period 30
mc_nsegments_per_clean = 4
mc_cleaning_interval = 0.25

This works for the hard drive, because it is too slow to really reach the 0.25 seconds anyway. The SSD on the other hand reaches the 0.25 seconds easily and that is probably too fast. So there is no time for the data to get invalidated and the GC moves too much data around. So my point is, that the results for the SSD are not to be trusted and that I need to repeat these measurements with different settings.

br,
Andreas Rohner
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): [email protected]

#68 lore raw
Quoted 9 lines · Andreas Rohner
Quoted 8 lines
Quoted 2 lines

You have to move the live blocks to a new segment, so you gain only (8 MB - live_blocks) of free space.

You always will have 8 MB after cleaning (garbage collection). So, all segments are identical from the free space point of view. What does GC check? And how can GC distinguish segments on the basis of free space? All cleaned segments return 8 MB free space for further allocation. So, all used segments will be over any threshold.

Quoted 9 lines

I am sorry if I wasn't clear enough. The invalidated blocks in a segment are basically unusable free space, that needs to be garbage collected. If you clean a segment you only gain the space of the invalidated blocks, from the perspective of the whole file system. Of course the whole segment is free after cleaning, but the live blocks were moved somewhere else and occupy space there. So from the perspective of the whole file system you only really gained the amount of space occupied by the invalidated blocks.

I suggest not to use "free blocks" term for the case of invalidated blocks. Because it is really confusing way. I suppose that we can use term "invalid blocks" or "dead blocks". But I think that "dead blocks" is not good way too. Because, from my point of view, invalidated blocks are blocks that keep previous state of actual blocks. Dead block sounds for me likewise unusable or bad block.

Quoted 13 lines
Quoted 13 lines
Quoted 12 lines
Quoted 7 lines
Quoted 5 lines

Although no blocks need to be moved, the SUFILE entry of the corresponding segment needs to be updated to avoid an infinite loop.

This is potentially useful for all gc policies, but it is especially beneficial for the timestamp policy.

I completely misunderstand this statement. What do you mean?

Well the timestamp policy always selects the oldest segment. If the oldest segment is below the threshold it won't be cleaned. If we don't change the timestamp it will be immediately selected again and it probably will still be below the threshold and so on in an infinite loop.

Quoted 5 lines
Quoted 3 lines

I understand your approach. But I misunderstand about what usefulness you are talking. What is it?

It helps to avoid unnecessary copy operations of data.

Ok. But how your implementation and approach can be used for timestamp policy implementation? Is it possible to combine GC policies into hybrid one?

Thanks,
Vyacheslav Dubeyko.

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 82ACC3FC-BE83-483F-99D8-D13F4D02C58F-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org

#70 lore raw
Quoted 22 lines · Vyacheslav Dubeyko
Quoted 9 lines · Andreas Rohner
Quoted 8 lines
Quoted 2 lines

You have to move the live blocks to a new segment, so you gain only (8 MB - live_blocks) of free space.

You always will have 8 MB after cleaning (garbage collection). So, all segments are identical from the free space point of view. What does GC check? And how can GC distinguish segments on the basis of free space? All cleaned segments return 8 MB free space for further allocation. So, all used segments will be over any threshold.

Quoted 9 lines

I am sorry if I wasn't clear enough. The invalidated blocks in a segment are basically unusable free space, that needs to be garbage collected. If you clean a segment you only gain the space of the invalidated blocks, from the perspective of the whole file system. Of course the whole segment is free after cleaning, but the live blocks were moved somewhere else and occupy space there. So from the perspective of the whole file system you only really gained the amount of space occupied by the invalidated blocks.

Quoted 6 lines

I suggest not to use "free blocks" term for the case of invalidated blocks. Because it is really confusing way. I suppose that we can use term "invalid blocks" or "dead blocks". But I think that "dead blocks" is not good way too. Because, from my point of view, invalidated blocks are blocks that keep previous state of actual blocks. Dead block sounds for me likewise unusable or bad block.

"free blocks" term sounds confusing. We often use terms "live" and "dead" for garbage collection, but "dead blocks" also sounds unfit to me as Vyacheslav pointed out.

How about "min reclaimable blocks" or "min collectable blocks" ?

Regards,
Ryusuke Konishi

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

A message that is not in the archive (sent off-list or not yet received): 20140126.155740.56352351.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org

#72 lore raw
Quoted 30 lines · Ryusuke Konishi
Quoted 22 lines · Vyacheslav Dubeyko
Quoted 9 lines · Andreas Rohner
Quoted 8 lines
Quoted 2 lines

You have to move the live blocks to a new segment, so you gain only (8 MB - live_blocks) of free space.

You always will have 8 MB after cleaning (garbage collection). So, all segments are identical from the free space point of view. What does GC check? And how can GC distinguish segments on the basis of free space? All cleaned segments return 8 MB free space for further allocation. So, all used segments will be over any threshold.

Quoted 9 lines

I am sorry if I wasn't clear enough. The invalidated blocks in a segment are basically unusable free space, that needs to be garbage collected. If you clean a segment you only gain the space of the invalidated blocks, from the perspective of the whole file system. Of course the whole segment is free after cleaning, but the live blocks were moved somewhere else and occupy space there. So from the perspective of the whole file system you only really gained the amount of space occupied by the invalidated blocks.

Quoted 6 lines

I suggest not to use "free blocks" term for the case of invalidated blocks. Because it is really confusing way. I suppose that we can use term "invalid blocks" or "dead blocks". But I think that "dead blocks" is not good way too. Because, from my point of view, invalidated blocks are blocks that keep previous state of actual blocks. Dead block sounds for me likewise unusable or bad block.

Quoted 5 lines

"free blocks" term sounds confusing. We often use terms "live" and "dead" for garbage collection, but "dead blocks" also sounds unfit to me as Vyacheslav pointed out.

How about "min reclaimable blocks" or "min collectable blocks" ?

Ok I will also change the config options accordingly. I like the term "reclaimable blocks".

Regards,
Andreas Rohner
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html