f2fs: fix potential overflow when adjusting GC cycle
authorChao Yu <yuchao0@huawei.com>
Mon, 7 Aug 2017 15:12:46 +0000 (23:12 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Tue, 15 Aug 2017 17:40:14 +0000 (10:40 -0700)
While comparing signed and unsigned variables, compiler will converts the
signed value to unsigned one, due to this reason, {in,de}crease_sleep_time
may return overflowed result.

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/gc.c
fs/f2fs/gc.h
include/trace/events/f2fs.h

index 8da7c14a9d29d7fc35f95a77533e243624e87ac8..e60480f71bb5aed5bcadc9fc1329e012216ed0a3 100644 (file)
@@ -28,7 +28,7 @@ static int gc_thread_func(void *data)
        struct f2fs_sb_info *sbi = data;
        struct f2fs_gc_kthread *gc_th = sbi->gc_thread;
        wait_queue_head_t *wq = &sbi->gc_thread->gc_wait_queue_head;
-       long wait_ms;
+       unsigned int wait_ms;
 
        wait_ms = gc_th->min_sleep_time;
 
index 57a9000ce3af62233d68b15c8db33ddaa168e18e..9325191fab2d6f4d571541c79c55ede3d5e47775 100644 (file)
@@ -69,25 +69,32 @@ static inline block_t limit_free_user_blocks(struct f2fs_sb_info *sbi)
 }
 
 static inline void increase_sleep_time(struct f2fs_gc_kthread *gc_th,
-                                                               long *wait)
+                                                       unsigned int *wait)
 {
+       unsigned int min_time = gc_th->min_sleep_time;
+       unsigned int max_time = gc_th->max_sleep_time;
+
        if (*wait == gc_th->no_gc_sleep_time)
                return;
 
-       *wait += gc_th->min_sleep_time;
-       if (*wait > gc_th->max_sleep_time)
-               *wait = gc_th->max_sleep_time;
+       if ((long long)*wait + (long long)min_time > (long long)max_time)
+               *wait = max_time;
+       else
+               *wait += min_time;
 }
 
 static inline void decrease_sleep_time(struct f2fs_gc_kthread *gc_th,
-                                                               long *wait)
+                                                       unsigned int *wait)
 {
+       unsigned int min_time = gc_th->min_sleep_time;
+
        if (*wait == gc_th->no_gc_sleep_time)
                *wait = gc_th->max_sleep_time;
 
-       *wait -= gc_th->min_sleep_time;
-       if (*wait <= gc_th->min_sleep_time)
-               *wait = gc_th->min_sleep_time;
+       if ((long long)*wait - (long long)min_time < (long long)min_time)
+               *wait = min_time;
+       else
+               *wait -= min_time;
 }
 
 static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi)
index 6f77a2755abbfa89b4ab93467d69d36364650693..db5c98256147d775a2d7169f82679cf71d4661af 100644 (file)
@@ -543,14 +543,14 @@ TRACE_EVENT(f2fs_map_blocks,
 
 TRACE_EVENT(f2fs_background_gc,
 
-       TP_PROTO(struct super_block *sb, long wait_ms,
+       TP_PROTO(struct super_block *sb, unsigned int wait_ms,
                        unsigned int prefree, unsigned int free),
 
        TP_ARGS(sb, wait_ms, prefree, free),
 
        TP_STRUCT__entry(
                __field(dev_t,  dev)
-               __field(long,   wait_ms)
+               __field(unsigned int,   wait_ms)
                __field(unsigned int,   prefree)
                __field(unsigned int,   free)
        ),
@@ -562,7 +562,7 @@ TRACE_EVENT(f2fs_background_gc,
                __entry->free           = free;
        ),
 
-       TP_printk("dev = (%d,%d), wait_ms = %ld, prefree = %u, free = %u",
+       TP_printk("dev = (%d,%d), wait_ms = %u, prefree = %u, free = %u",
                show_dev(__entry->dev),
                __entry->wait_ms,
                __entry->prefree,