1 From dd71cf6b2773310b01c6fe6c773064c80fd2476b Mon Sep 17 00:00:00 2001
2 From: NeilBrown <neilb@suse.de>
3 Date: Thu, 7 May 2009 12:49:35 +1000
4 Subject: [PATCH] md: tidy up status_resync to handle large arrays.
6 Two problems in status_resync.
7 1/ It still used Kilobytes as the basic block unit, while most code
8 now uses sectors uniformly.
9 2/ It doesn't allow for the possibility that max_sectors exceeds
10 the range of "unsigned long".
13 - change "max_blocks" to "max_sectors", and store sector numbers
14 in there and in 'resync'
15 - Make 'rt' a 'sector_t' so it can temporarily hold the number of
17 - use sector_div rather than normal division.
18 - change the magic '100' used to preserve precision to '32'.
19 + making it a power of 2 makes division easier
20 + it doesn't need to be as large as it was chosen when we averaged
21 speed over the entire run. Now we average speed over the last 30
24 Reported-by: "Mario 'BitKoenig' Holbe" <Mario.Holbe@TU-Ilmenau.DE>
25 Signed-off-by: NeilBrown <neilb@suse.de>
27 drivers/md/md.c | 45 ++++++++++++++++++++++++++++-----------------
28 1 file changed, 28 insertions(+), 17 deletions(-)
30 --- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c
31 +++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c
32 @@ -5340,37 +5340,38 @@ static void status_unused(struct seq_fil
34 static void status_resync(struct seq_file *seq, mddev_t * mddev)
36 - sector_t max_blocks, resync, res;
37 - unsigned long dt, db, rt;
38 + sector_t max_sectors, resync, res;
39 + unsigned long dt, db;
42 unsigned int per_milli;
44 - resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2;
45 + resync = mddev->curr_resync - atomic_read(&mddev->recovery_active);
47 if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
48 - max_blocks = mddev->resync_max_sectors >> 1;
49 + max_sectors = mddev->resync_max_sectors;
51 - max_blocks = mddev->size;
52 + max_sectors = mddev->size << 1;
62 /* Pick 'scale' such that (resync>>scale)*1000 will fit
63 - * in a sector_t, and (max_blocks>>scale) will fit in a
64 + * in a sector_t, and (max_sectors>>scale) will fit in a
65 * u32, as those are the requirements for sector_div.
66 * Thus 'scale' must be at least 10
69 if (sizeof(sector_t) > sizeof(unsigned long)) {
70 - while ( max_blocks/2 > (1ULL<<(scale+32)))
71 + while ( max_sectors/2 > (1ULL<<(scale+32)))
74 res = (resync>>scale)*1000;
75 - sector_div(res, (u32)((max_blocks>>scale)+1));
76 + sector_div(res, (u32)((max_sectors>>scale)+1));
80 @@ -5391,25 +5392,35 @@ static void status_resync(struct seq_fil
81 (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ?
82 "resync" : "recovery"))),
83 per_milli/10, per_milli % 10,
84 - (unsigned long long) resync,
85 - (unsigned long long) max_blocks);
86 + (unsigned long long) resync/2,
87 + (unsigned long long) max_sectors/2);
90 - * We do not want to overflow, so the order of operands and
91 - * the * 100 / 100 trick are important. We do a +1 to be
92 - * safe against division by zero. We only estimate anyway.
94 * dt: time from mark until now
95 * db: blocks written from mark until now
98 + * rt is a sector_t, so could be 32bit or 64bit.
99 + * So we divide before multiply in case it is 32bit and close
101 + * We scale the divisor (db) by 32 to avoid loosing precision
102 + * near the end of resync when the number of remaining sectors
103 + * is close to 'db'.
104 + * We then divide rt by 32 after multiplying by db to compensate.
105 + * The '+1' avoids division by zero if db is very small.
107 dt = ((jiffies - mddev->resync_mark) / HZ);
109 db = (mddev->curr_mark_cnt - atomic_read(&mddev->recovery_active))
110 - mddev->resync_mark_cnt;
111 - rt = (dt * ((unsigned long)(max_blocks-resync) / (db/2/100+1)))/100;
113 - seq_printf(seq, " finish=%lu.%lumin", rt / 60, (rt % 60)/6);
114 + rt = max_sectors - resync; /* number of remaining sectors */
115 + sector_div(rt, db/32+1);
119 + seq_printf(seq, " finish=%lu.%lumin", (unsigned long)rt / 60,
120 + ((unsigned long)rt % 60)/6);
122 seq_printf(seq, " speed=%ldK/sec", db/2/dt);