]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/patches/suse-2.6.27.25/patches.fixes/0024-md-tidy-up-status_resync-to-handle-large-arrays.patch
Reenabled linux-xen and xen-image build
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.fixes / 0024-md-tidy-up-status_resync-to-handle-large-arrays.patch
CommitLineData
00e5a55c
BS
1From dd71cf6b2773310b01c6fe6c773064c80fd2476b Mon Sep 17 00:00:00 2001
2From: NeilBrown <neilb@suse.de>
3Date: Thu, 7 May 2009 12:49:35 +1000
4Subject: [PATCH] md: tidy up status_resync to handle large arrays.
5
6Two problems in status_resync.
71/ It still used Kilobytes as the basic block unit, while most code
8 now uses sectors uniformly.
92/ It doesn't allow for the possibility that max_sectors exceeds
10 the range of "unsigned long".
11
12So
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
16 remaining sectors.
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
22 seconds or so.
23
24Reported-by: "Mario 'BitKoenig' Holbe" <Mario.Holbe@TU-Ilmenau.DE>
25Signed-off-by: NeilBrown <neilb@suse.de>
26---
27 drivers/md/md.c | 45 ++++++++++++++++++++++++++++-----------------
28 1 file changed, 28 insertions(+), 17 deletions(-)
29
30--- a/drivers/md/md.c
31+++ b/drivers/md/md.c
32@@ -5257,37 +5257,38 @@ static void status_unused(struct seq_fil
33
34 static void status_resync(struct seq_file *seq, mddev_t * mddev)
35 {
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;
40+ sector_t rt;
41 int scale;
42 unsigned int per_milli;
43
44- resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2;
45+ resync = mddev->curr_resync - atomic_read(&mddev->recovery_active);
46
47 if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
48- max_blocks = mddev->resync_max_sectors >> 1;
49+ max_sectors = mddev->resync_max_sectors;
50 else
51- max_blocks = mddev->size;
52+ max_sectors = mddev->size;
53
54 /*
55 * Should not happen.
56 */
57- if (!max_blocks) {
58+ if (!max_sectors) {
59 MD_BUG();
60 return;
61 }
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
67 */
68 scale = 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)))
72 scale++;
73 }
74 res = (resync>>scale)*1000;
75- sector_div(res, (u32)((max_blocks>>scale)+1));
76+ sector_div(res, (u32)((max_sectors>>scale)+1));
77
78 per_milli = res;
79 {
80@@ -5308,25 +5309,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);
88
89 /*
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.
93- *
94 * dt: time from mark until now
95 * db: blocks written from mark until now
96 * rt: remaining time
97+ *
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
100+ * to the limit.
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.
106 */
107 dt = ((jiffies - mddev->resync_mark) / HZ);
108 if (!dt) dt++;
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;
112
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);
116+ rt *= dt;
117+ rt >>= 5;
118+
119+ seq_printf(seq, " finish=%lu.%lumin", (unsigned long)rt / 60,
120+ ((unsigned long)rt % 60)/6);
121
122 seq_printf(seq, " speed=%ldK/sec", db/2/dt);
123 }