]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
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. | |
5 | ||
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". | |
11 | ||
12 | So | |
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 | ||
24 | Reported-by: "Mario 'BitKoenig' Holbe" <Mario.Holbe@TU-Ilmenau.DE> | |
25 | Signed-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 | } |