PM / Hibernate: Migrate to ktime_t

This patch migrates swsusp_show_speed and its callers to using ktime_t instead
of 'struct timeval' which suffers from the y2038 problem.

Changes to swsusp_show_speed:
        - use ktime_t for start and stop times
        - pass start and stop times by value
Calling functions affected:
        - load_image
        - load_image_lzo
        - save_image
        - save_image_lzo
        - hibernate_preallocate_memory
Design decisions:
        - use ktime_t to preserve same granularity of reporting as before
        - use centisecs logic as before to avoid 'div by zero' issues caused by
          using seconds and nanoseconds directly
        - use monotonic time (ktime_get()) since we only care about elapsed time.

Signed-off-by: Tina Ruchandani <ruchandani.tina@gmail.com>
Suggested-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
Tina Ruchandani 2014-10-30 11:04:53 -07:00 коммит произвёл Rafael J. Wysocki
Родитель 0df1f2487d
Коммит db59760582
4 изменённых файлов: 33 добавлений и 34 удалений

Просмотреть файл

@ -28,6 +28,7 @@
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/genhd.h> #include <linux/genhd.h>
#include <linux/ktime.h>
#include <trace/events/power.h> #include <trace/events/power.h>
#include "power.h" #include "power.h"
@ -232,20 +233,17 @@ static void platform_recover(int platform_mode)
* @nr_pages: Number of memory pages processed between @start and @stop. * @nr_pages: Number of memory pages processed between @start and @stop.
* @msg: Additional diagnostic message to print. * @msg: Additional diagnostic message to print.
*/ */
void swsusp_show_speed(struct timeval *start, struct timeval *stop, void swsusp_show_speed(ktime_t start, ktime_t stop,
unsigned nr_pages, char *msg) unsigned nr_pages, char *msg)
{ {
ktime_t diff;
u64 elapsed_centisecs64; u64 elapsed_centisecs64;
unsigned int centisecs; unsigned int centisecs;
unsigned int k; unsigned int k;
unsigned int kps; unsigned int kps;
elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start); diff = ktime_sub(stop, start);
/* elapsed_centisecs64 = ktime_divns(diff, 10*NSEC_PER_MSEC);
* If "(s64)elapsed_centisecs64 < 0", it will print long elapsed time,
* it is obvious enough for what went wrong.
*/
do_div(elapsed_centisecs64, NSEC_PER_SEC / 100);
centisecs = elapsed_centisecs64; centisecs = elapsed_centisecs64;
if (centisecs == 0) if (centisecs == 0)
centisecs = 1; /* avoid div-by-zero */ centisecs = 1; /* avoid div-by-zero */

Просмотреть файл

@ -174,8 +174,7 @@ extern int hib_wait_on_bio_chain(struct bio **bio_chain);
struct timeval; struct timeval;
/* kernel/power/swsusp.c */ /* kernel/power/swsusp.c */
extern void swsusp_show_speed(struct timeval *, struct timeval *, extern void swsusp_show_speed(ktime_t, ktime_t, unsigned int, char *);
unsigned int, char *);
#ifdef CONFIG_SUSPEND #ifdef CONFIG_SUSPEND
/* kernel/power/suspend.c */ /* kernel/power/suspend.c */

Просмотреть файл

@ -28,6 +28,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/ktime.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
@ -1576,11 +1577,11 @@ int hibernate_preallocate_memory(void)
struct zone *zone; struct zone *zone;
unsigned long saveable, size, max_size, count, highmem, pages = 0; unsigned long saveable, size, max_size, count, highmem, pages = 0;
unsigned long alloc, save_highmem, pages_highmem, avail_normal; unsigned long alloc, save_highmem, pages_highmem, avail_normal;
struct timeval start, stop; ktime_t start, stop;
int error; int error;
printk(KERN_INFO "PM: Preallocating image memory... "); printk(KERN_INFO "PM: Preallocating image memory... ");
do_gettimeofday(&start); start = ktime_get();
error = memory_bm_create(&orig_bm, GFP_IMAGE, PG_ANY); error = memory_bm_create(&orig_bm, GFP_IMAGE, PG_ANY);
if (error) if (error)
@ -1709,9 +1710,9 @@ int hibernate_preallocate_memory(void)
free_unnecessary_pages(); free_unnecessary_pages();
out: out:
do_gettimeofday(&stop); stop = ktime_get();
printk(KERN_CONT "done (allocated %lu pages)\n", pages); printk(KERN_CONT "done (allocated %lu pages)\n", pages);
swsusp_show_speed(&start, &stop, pages, "Allocated"); swsusp_show_speed(start, stop, pages, "Allocated");
return 0; return 0;

Просмотреть файл

@ -30,6 +30,7 @@
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/ktime.h>
#include "power.h" #include "power.h"
@ -445,8 +446,8 @@ static int save_image(struct swap_map_handle *handle,
int nr_pages; int nr_pages;
int err2; int err2;
struct bio *bio; struct bio *bio;
struct timeval start; ktime_t start;
struct timeval stop; ktime_t stop;
printk(KERN_INFO "PM: Saving image data pages (%u pages)...\n", printk(KERN_INFO "PM: Saving image data pages (%u pages)...\n",
nr_to_write); nr_to_write);
@ -455,7 +456,7 @@ static int save_image(struct swap_map_handle *handle,
m = 1; m = 1;
nr_pages = 0; nr_pages = 0;
bio = NULL; bio = NULL;
do_gettimeofday(&start); start = ktime_get();
while (1) { while (1) {
ret = snapshot_read_next(snapshot); ret = snapshot_read_next(snapshot);
if (ret <= 0) if (ret <= 0)
@ -469,12 +470,12 @@ static int save_image(struct swap_map_handle *handle,
nr_pages++; nr_pages++;
} }
err2 = hib_wait_on_bio_chain(&bio); err2 = hib_wait_on_bio_chain(&bio);
do_gettimeofday(&stop); stop = ktime_get();
if (!ret) if (!ret)
ret = err2; ret = err2;
if (!ret) if (!ret)
printk(KERN_INFO "PM: Image saving done.\n"); printk(KERN_INFO "PM: Image saving done.\n");
swsusp_show_speed(&start, &stop, nr_to_write, "Wrote"); swsusp_show_speed(start, stop, nr_to_write, "Wrote");
return ret; return ret;
} }
@ -580,8 +581,8 @@ static int save_image_lzo(struct swap_map_handle *handle,
int nr_pages; int nr_pages;
int err2; int err2;
struct bio *bio; struct bio *bio;
struct timeval start; ktime_t start;
struct timeval stop; ktime_t stop;
size_t off; size_t off;
unsigned thr, run_threads, nr_threads; unsigned thr, run_threads, nr_threads;
unsigned char *page = NULL; unsigned char *page = NULL;
@ -674,7 +675,7 @@ static int save_image_lzo(struct swap_map_handle *handle,
m = 1; m = 1;
nr_pages = 0; nr_pages = 0;
bio = NULL; bio = NULL;
do_gettimeofday(&start); start = ktime_get();
for (;;) { for (;;) {
for (thr = 0; thr < nr_threads; thr++) { for (thr = 0; thr < nr_threads; thr++) {
for (off = 0; off < LZO_UNC_SIZE; off += PAGE_SIZE) { for (off = 0; off < LZO_UNC_SIZE; off += PAGE_SIZE) {
@ -759,12 +760,12 @@ static int save_image_lzo(struct swap_map_handle *handle,
out_finish: out_finish:
err2 = hib_wait_on_bio_chain(&bio); err2 = hib_wait_on_bio_chain(&bio);
do_gettimeofday(&stop); stop = ktime_get();
if (!ret) if (!ret)
ret = err2; ret = err2;
if (!ret) if (!ret)
printk(KERN_INFO "PM: Image saving done.\n"); printk(KERN_INFO "PM: Image saving done.\n");
swsusp_show_speed(&start, &stop, nr_to_write, "Wrote"); swsusp_show_speed(start, stop, nr_to_write, "Wrote");
out_clean: out_clean:
if (crc) { if (crc) {
if (crc->thr) if (crc->thr)
@ -965,8 +966,8 @@ static int load_image(struct swap_map_handle *handle,
{ {
unsigned int m; unsigned int m;
int ret = 0; int ret = 0;
struct timeval start; ktime_t start;
struct timeval stop; ktime_t stop;
struct bio *bio; struct bio *bio;
int err2; int err2;
unsigned nr_pages; unsigned nr_pages;
@ -978,7 +979,7 @@ static int load_image(struct swap_map_handle *handle,
m = 1; m = 1;
nr_pages = 0; nr_pages = 0;
bio = NULL; bio = NULL;
do_gettimeofday(&start); start = ktime_get();
for ( ; ; ) { for ( ; ; ) {
ret = snapshot_write_next(snapshot); ret = snapshot_write_next(snapshot);
if (ret <= 0) if (ret <= 0)
@ -996,7 +997,7 @@ static int load_image(struct swap_map_handle *handle,
nr_pages++; nr_pages++;
} }
err2 = hib_wait_on_bio_chain(&bio); err2 = hib_wait_on_bio_chain(&bio);
do_gettimeofday(&stop); stop = ktime_get();
if (!ret) if (!ret)
ret = err2; ret = err2;
if (!ret) { if (!ret) {
@ -1005,7 +1006,7 @@ static int load_image(struct swap_map_handle *handle,
if (!snapshot_image_loaded(snapshot)) if (!snapshot_image_loaded(snapshot))
ret = -ENODATA; ret = -ENODATA;
} }
swsusp_show_speed(&start, &stop, nr_to_read, "Read"); swsusp_show_speed(start, stop, nr_to_read, "Read");
return ret; return ret;
} }
@ -1067,8 +1068,8 @@ static int load_image_lzo(struct swap_map_handle *handle,
int ret = 0; int ret = 0;
int eof = 0; int eof = 0;
struct bio *bio; struct bio *bio;
struct timeval start; ktime_t start;
struct timeval stop; ktime_t stop;
unsigned nr_pages; unsigned nr_pages;
size_t off; size_t off;
unsigned i, thr, run_threads, nr_threads; unsigned i, thr, run_threads, nr_threads;
@ -1190,7 +1191,7 @@ static int load_image_lzo(struct swap_map_handle *handle,
m = 1; m = 1;
nr_pages = 0; nr_pages = 0;
bio = NULL; bio = NULL;
do_gettimeofday(&start); start = ktime_get();
ret = snapshot_write_next(snapshot); ret = snapshot_write_next(snapshot);
if (ret <= 0) if (ret <= 0)
@ -1343,7 +1344,7 @@ out_finish:
wait_event(crc->done, atomic_read(&crc->stop)); wait_event(crc->done, atomic_read(&crc->stop));
atomic_set(&crc->stop, 0); atomic_set(&crc->stop, 0);
} }
do_gettimeofday(&stop); stop = ktime_get();
if (!ret) { if (!ret) {
printk(KERN_INFO "PM: Image loading done.\n"); printk(KERN_INFO "PM: Image loading done.\n");
snapshot_write_finalize(snapshot); snapshot_write_finalize(snapshot);
@ -1359,7 +1360,7 @@ out_finish:
} }
} }
} }
swsusp_show_speed(&start, &stop, nr_to_read, "Read"); swsusp_show_speed(start, stop, nr_to_read, "Read");
out_clean: out_clean:
for (i = 0; i < ring_size; i++) for (i = 0; i < ring_size; i++)
free_page((unsigned long)page[i]); free_page((unsigned long)page[i]);