1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Bad block management
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * - Heavily based on MD badblocks code from Neil Brown
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Copyright (c) 2015, Intel Corporation.
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/badblocks.h>
11*4882a593Smuzhiyun #include <linux/seqlock.h>
12*4882a593Smuzhiyun #include <linux/device.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/stddef.h>
16*4882a593Smuzhiyun #include <linux/types.h>
17*4882a593Smuzhiyun #include <linux/slab.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun /**
20*4882a593Smuzhiyun * badblocks_check() - check a given range for bad sectors
21*4882a593Smuzhiyun * @bb: the badblocks structure that holds all badblock information
22*4882a593Smuzhiyun * @s: sector (start) at which to check for badblocks
23*4882a593Smuzhiyun * @sectors: number of sectors to check for badblocks
24*4882a593Smuzhiyun * @first_bad: pointer to store location of the first badblock
25*4882a593Smuzhiyun * @bad_sectors: pointer to store number of badblocks after @first_bad
26*4882a593Smuzhiyun *
27*4882a593Smuzhiyun * We can record which blocks on each device are 'bad' and so just
28*4882a593Smuzhiyun * fail those blocks, or that stripe, rather than the whole device.
29*4882a593Smuzhiyun * Entries in the bad-block table are 64bits wide. This comprises:
30*4882a593Smuzhiyun * Length of bad-range, in sectors: 0-511 for lengths 1-512
31*4882a593Smuzhiyun * Start of bad-range, sector offset, 54 bits (allows 8 exbibytes)
32*4882a593Smuzhiyun * A 'shift' can be set so that larger blocks are tracked and
33*4882a593Smuzhiyun * consequently larger devices can be covered.
34*4882a593Smuzhiyun * 'Acknowledged' flag - 1 bit. - the most significant bit.
35*4882a593Smuzhiyun *
36*4882a593Smuzhiyun * Locking of the bad-block table uses a seqlock so badblocks_check
37*4882a593Smuzhiyun * might need to retry if it is very unlucky.
38*4882a593Smuzhiyun * We will sometimes want to check for bad blocks in a bi_end_io function,
39*4882a593Smuzhiyun * so we use the write_seqlock_irq variant.
40*4882a593Smuzhiyun *
41*4882a593Smuzhiyun * When looking for a bad block we specify a range and want to
42*4882a593Smuzhiyun * know if any block in the range is bad. So we binary-search
43*4882a593Smuzhiyun * to the last range that starts at-or-before the given endpoint,
44*4882a593Smuzhiyun * (or "before the sector after the target range")
45*4882a593Smuzhiyun * then see if it ends after the given start.
46*4882a593Smuzhiyun *
47*4882a593Smuzhiyun * Return:
48*4882a593Smuzhiyun * 0: there are no known bad blocks in the range
49*4882a593Smuzhiyun * 1: there are known bad block which are all acknowledged
50*4882a593Smuzhiyun * -1: there are bad blocks which have not yet been acknowledged in metadata.
51*4882a593Smuzhiyun * plus the start/length of the first bad section we overlap.
52*4882a593Smuzhiyun */
badblocks_check(struct badblocks * bb,sector_t s,int sectors,sector_t * first_bad,int * bad_sectors)53*4882a593Smuzhiyun int badblocks_check(struct badblocks *bb, sector_t s, int sectors,
54*4882a593Smuzhiyun sector_t *first_bad, int *bad_sectors)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun int hi;
57*4882a593Smuzhiyun int lo;
58*4882a593Smuzhiyun u64 *p = bb->page;
59*4882a593Smuzhiyun int rv;
60*4882a593Smuzhiyun sector_t target = s + sectors;
61*4882a593Smuzhiyun unsigned seq;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun if (bb->shift > 0) {
64*4882a593Smuzhiyun /* round the start down, and the end up */
65*4882a593Smuzhiyun s >>= bb->shift;
66*4882a593Smuzhiyun target += (1<<bb->shift) - 1;
67*4882a593Smuzhiyun target >>= bb->shift;
68*4882a593Smuzhiyun sectors = target - s;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun /* 'target' is now the first block after the bad range */
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun retry:
73*4882a593Smuzhiyun seq = read_seqbegin(&bb->lock);
74*4882a593Smuzhiyun lo = 0;
75*4882a593Smuzhiyun rv = 0;
76*4882a593Smuzhiyun hi = bb->count;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun /* Binary search between lo and hi for 'target'
79*4882a593Smuzhiyun * i.e. for the last range that starts before 'target'
80*4882a593Smuzhiyun */
81*4882a593Smuzhiyun /* INVARIANT: ranges before 'lo' and at-or-after 'hi'
82*4882a593Smuzhiyun * are known not to be the last range before target.
83*4882a593Smuzhiyun * VARIANT: hi-lo is the number of possible
84*4882a593Smuzhiyun * ranges, and decreases until it reaches 1
85*4882a593Smuzhiyun */
86*4882a593Smuzhiyun while (hi - lo > 1) {
87*4882a593Smuzhiyun int mid = (lo + hi) / 2;
88*4882a593Smuzhiyun sector_t a = BB_OFFSET(p[mid]);
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun if (a < target)
91*4882a593Smuzhiyun /* This could still be the one, earlier ranges
92*4882a593Smuzhiyun * could not.
93*4882a593Smuzhiyun */
94*4882a593Smuzhiyun lo = mid;
95*4882a593Smuzhiyun else
96*4882a593Smuzhiyun /* This and later ranges are definitely out. */
97*4882a593Smuzhiyun hi = mid;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun /* 'lo' might be the last that started before target, but 'hi' isn't */
100*4882a593Smuzhiyun if (hi > lo) {
101*4882a593Smuzhiyun /* need to check all range that end after 's' to see if
102*4882a593Smuzhiyun * any are unacknowledged.
103*4882a593Smuzhiyun */
104*4882a593Smuzhiyun while (lo >= 0 &&
105*4882a593Smuzhiyun BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) {
106*4882a593Smuzhiyun if (BB_OFFSET(p[lo]) < target) {
107*4882a593Smuzhiyun /* starts before the end, and finishes after
108*4882a593Smuzhiyun * the start, so they must overlap
109*4882a593Smuzhiyun */
110*4882a593Smuzhiyun if (rv != -1 && BB_ACK(p[lo]))
111*4882a593Smuzhiyun rv = 1;
112*4882a593Smuzhiyun else
113*4882a593Smuzhiyun rv = -1;
114*4882a593Smuzhiyun *first_bad = BB_OFFSET(p[lo]);
115*4882a593Smuzhiyun *bad_sectors = BB_LEN(p[lo]);
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun lo--;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun if (read_seqretry(&bb->lock, seq))
122*4882a593Smuzhiyun goto retry;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun return rv;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(badblocks_check);
127*4882a593Smuzhiyun
badblocks_update_acked(struct badblocks * bb)128*4882a593Smuzhiyun static void badblocks_update_acked(struct badblocks *bb)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun u64 *p = bb->page;
131*4882a593Smuzhiyun int i;
132*4882a593Smuzhiyun bool unacked = false;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun if (!bb->unacked_exist)
135*4882a593Smuzhiyun return;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun for (i = 0; i < bb->count ; i++) {
138*4882a593Smuzhiyun if (!BB_ACK(p[i])) {
139*4882a593Smuzhiyun unacked = true;
140*4882a593Smuzhiyun break;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun if (!unacked)
145*4882a593Smuzhiyun bb->unacked_exist = 0;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun /**
149*4882a593Smuzhiyun * badblocks_set() - Add a range of bad blocks to the table.
150*4882a593Smuzhiyun * @bb: the badblocks structure that holds all badblock information
151*4882a593Smuzhiyun * @s: first sector to mark as bad
152*4882a593Smuzhiyun * @sectors: number of sectors to mark as bad
153*4882a593Smuzhiyun * @acknowledged: weather to mark the bad sectors as acknowledged
154*4882a593Smuzhiyun *
155*4882a593Smuzhiyun * This might extend the table, or might contract it if two adjacent ranges
156*4882a593Smuzhiyun * can be merged. We binary-search to find the 'insertion' point, then
157*4882a593Smuzhiyun * decide how best to handle it.
158*4882a593Smuzhiyun *
159*4882a593Smuzhiyun * Return:
160*4882a593Smuzhiyun * 0: success
161*4882a593Smuzhiyun * 1: failed to set badblocks (out of space)
162*4882a593Smuzhiyun */
badblocks_set(struct badblocks * bb,sector_t s,int sectors,int acknowledged)163*4882a593Smuzhiyun int badblocks_set(struct badblocks *bb, sector_t s, int sectors,
164*4882a593Smuzhiyun int acknowledged)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun u64 *p;
167*4882a593Smuzhiyun int lo, hi;
168*4882a593Smuzhiyun int rv = 0;
169*4882a593Smuzhiyun unsigned long flags;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun if (bb->shift < 0)
172*4882a593Smuzhiyun /* badblocks are disabled */
173*4882a593Smuzhiyun return 1;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun if (bb->shift) {
176*4882a593Smuzhiyun /* round the start down, and the end up */
177*4882a593Smuzhiyun sector_t next = s + sectors;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun s >>= bb->shift;
180*4882a593Smuzhiyun next += (1<<bb->shift) - 1;
181*4882a593Smuzhiyun next >>= bb->shift;
182*4882a593Smuzhiyun sectors = next - s;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun write_seqlock_irqsave(&bb->lock, flags);
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun p = bb->page;
188*4882a593Smuzhiyun lo = 0;
189*4882a593Smuzhiyun hi = bb->count;
190*4882a593Smuzhiyun /* Find the last range that starts at-or-before 's' */
191*4882a593Smuzhiyun while (hi - lo > 1) {
192*4882a593Smuzhiyun int mid = (lo + hi) / 2;
193*4882a593Smuzhiyun sector_t a = BB_OFFSET(p[mid]);
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun if (a <= s)
196*4882a593Smuzhiyun lo = mid;
197*4882a593Smuzhiyun else
198*4882a593Smuzhiyun hi = mid;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun if (hi > lo && BB_OFFSET(p[lo]) > s)
201*4882a593Smuzhiyun hi = lo;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun if (hi > lo) {
204*4882a593Smuzhiyun /* we found a range that might merge with the start
205*4882a593Smuzhiyun * of our new range
206*4882a593Smuzhiyun */
207*4882a593Smuzhiyun sector_t a = BB_OFFSET(p[lo]);
208*4882a593Smuzhiyun sector_t e = a + BB_LEN(p[lo]);
209*4882a593Smuzhiyun int ack = BB_ACK(p[lo]);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun if (e >= s) {
212*4882a593Smuzhiyun /* Yes, we can merge with a previous range */
213*4882a593Smuzhiyun if (s == a && s + sectors >= e)
214*4882a593Smuzhiyun /* new range covers old */
215*4882a593Smuzhiyun ack = acknowledged;
216*4882a593Smuzhiyun else
217*4882a593Smuzhiyun ack = ack && acknowledged;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun if (e < s + sectors)
220*4882a593Smuzhiyun e = s + sectors;
221*4882a593Smuzhiyun if (e - a <= BB_MAX_LEN) {
222*4882a593Smuzhiyun p[lo] = BB_MAKE(a, e-a, ack);
223*4882a593Smuzhiyun s = e;
224*4882a593Smuzhiyun } else {
225*4882a593Smuzhiyun /* does not all fit in one range,
226*4882a593Smuzhiyun * make p[lo] maximal
227*4882a593Smuzhiyun */
228*4882a593Smuzhiyun if (BB_LEN(p[lo]) != BB_MAX_LEN)
229*4882a593Smuzhiyun p[lo] = BB_MAKE(a, BB_MAX_LEN, ack);
230*4882a593Smuzhiyun s = a + BB_MAX_LEN;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun sectors = e - s;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun if (sectors && hi < bb->count) {
236*4882a593Smuzhiyun /* 'hi' points to the first range that starts after 's'.
237*4882a593Smuzhiyun * Maybe we can merge with the start of that range
238*4882a593Smuzhiyun */
239*4882a593Smuzhiyun sector_t a = BB_OFFSET(p[hi]);
240*4882a593Smuzhiyun sector_t e = a + BB_LEN(p[hi]);
241*4882a593Smuzhiyun int ack = BB_ACK(p[hi]);
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun if (a <= s + sectors) {
244*4882a593Smuzhiyun /* merging is possible */
245*4882a593Smuzhiyun if (e <= s + sectors) {
246*4882a593Smuzhiyun /* full overlap */
247*4882a593Smuzhiyun e = s + sectors;
248*4882a593Smuzhiyun ack = acknowledged;
249*4882a593Smuzhiyun } else
250*4882a593Smuzhiyun ack = ack && acknowledged;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun a = s;
253*4882a593Smuzhiyun if (e - a <= BB_MAX_LEN) {
254*4882a593Smuzhiyun p[hi] = BB_MAKE(a, e-a, ack);
255*4882a593Smuzhiyun s = e;
256*4882a593Smuzhiyun } else {
257*4882a593Smuzhiyun p[hi] = BB_MAKE(a, BB_MAX_LEN, ack);
258*4882a593Smuzhiyun s = a + BB_MAX_LEN;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun sectors = e - s;
261*4882a593Smuzhiyun lo = hi;
262*4882a593Smuzhiyun hi++;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun if (sectors == 0 && hi < bb->count) {
266*4882a593Smuzhiyun /* we might be able to combine lo and hi */
267*4882a593Smuzhiyun /* Note: 's' is at the end of 'lo' */
268*4882a593Smuzhiyun sector_t a = BB_OFFSET(p[hi]);
269*4882a593Smuzhiyun int lolen = BB_LEN(p[lo]);
270*4882a593Smuzhiyun int hilen = BB_LEN(p[hi]);
271*4882a593Smuzhiyun int newlen = lolen + hilen - (s - a);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun if (s >= a && newlen < BB_MAX_LEN) {
274*4882a593Smuzhiyun /* yes, we can combine them */
275*4882a593Smuzhiyun int ack = BB_ACK(p[lo]) && BB_ACK(p[hi]);
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun p[lo] = BB_MAKE(BB_OFFSET(p[lo]), newlen, ack);
278*4882a593Smuzhiyun memmove(p + hi, p + hi + 1,
279*4882a593Smuzhiyun (bb->count - hi - 1) * 8);
280*4882a593Smuzhiyun bb->count--;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun while (sectors) {
284*4882a593Smuzhiyun /* didn't merge (it all).
285*4882a593Smuzhiyun * Need to add a range just before 'hi'
286*4882a593Smuzhiyun */
287*4882a593Smuzhiyun if (bb->count >= MAX_BADBLOCKS) {
288*4882a593Smuzhiyun /* No room for more */
289*4882a593Smuzhiyun rv = 1;
290*4882a593Smuzhiyun break;
291*4882a593Smuzhiyun } else {
292*4882a593Smuzhiyun int this_sectors = sectors;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun memmove(p + hi + 1, p + hi,
295*4882a593Smuzhiyun (bb->count - hi) * 8);
296*4882a593Smuzhiyun bb->count++;
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun if (this_sectors > BB_MAX_LEN)
299*4882a593Smuzhiyun this_sectors = BB_MAX_LEN;
300*4882a593Smuzhiyun p[hi] = BB_MAKE(s, this_sectors, acknowledged);
301*4882a593Smuzhiyun sectors -= this_sectors;
302*4882a593Smuzhiyun s += this_sectors;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun bb->changed = 1;
307*4882a593Smuzhiyun if (!acknowledged)
308*4882a593Smuzhiyun bb->unacked_exist = 1;
309*4882a593Smuzhiyun else
310*4882a593Smuzhiyun badblocks_update_acked(bb);
311*4882a593Smuzhiyun write_sequnlock_irqrestore(&bb->lock, flags);
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun return rv;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(badblocks_set);
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun /**
318*4882a593Smuzhiyun * badblocks_clear() - Remove a range of bad blocks to the table.
319*4882a593Smuzhiyun * @bb: the badblocks structure that holds all badblock information
320*4882a593Smuzhiyun * @s: first sector to mark as bad
321*4882a593Smuzhiyun * @sectors: number of sectors to mark as bad
322*4882a593Smuzhiyun *
323*4882a593Smuzhiyun * This may involve extending the table if we spilt a region,
324*4882a593Smuzhiyun * but it must not fail. So if the table becomes full, we just
325*4882a593Smuzhiyun * drop the remove request.
326*4882a593Smuzhiyun *
327*4882a593Smuzhiyun * Return:
328*4882a593Smuzhiyun * 0: success
329*4882a593Smuzhiyun * 1: failed to clear badblocks
330*4882a593Smuzhiyun */
badblocks_clear(struct badblocks * bb,sector_t s,int sectors)331*4882a593Smuzhiyun int badblocks_clear(struct badblocks *bb, sector_t s, int sectors)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun u64 *p;
334*4882a593Smuzhiyun int lo, hi;
335*4882a593Smuzhiyun sector_t target = s + sectors;
336*4882a593Smuzhiyun int rv = 0;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun if (bb->shift > 0) {
339*4882a593Smuzhiyun /* When clearing we round the start up and the end down.
340*4882a593Smuzhiyun * This should not matter as the shift should align with
341*4882a593Smuzhiyun * the block size and no rounding should ever be needed.
342*4882a593Smuzhiyun * However it is better the think a block is bad when it
343*4882a593Smuzhiyun * isn't than to think a block is not bad when it is.
344*4882a593Smuzhiyun */
345*4882a593Smuzhiyun s += (1<<bb->shift) - 1;
346*4882a593Smuzhiyun s >>= bb->shift;
347*4882a593Smuzhiyun target >>= bb->shift;
348*4882a593Smuzhiyun sectors = target - s;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun write_seqlock_irq(&bb->lock);
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun p = bb->page;
354*4882a593Smuzhiyun lo = 0;
355*4882a593Smuzhiyun hi = bb->count;
356*4882a593Smuzhiyun /* Find the last range that starts before 'target' */
357*4882a593Smuzhiyun while (hi - lo > 1) {
358*4882a593Smuzhiyun int mid = (lo + hi) / 2;
359*4882a593Smuzhiyun sector_t a = BB_OFFSET(p[mid]);
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun if (a < target)
362*4882a593Smuzhiyun lo = mid;
363*4882a593Smuzhiyun else
364*4882a593Smuzhiyun hi = mid;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun if (hi > lo) {
367*4882a593Smuzhiyun /* p[lo] is the last range that could overlap the
368*4882a593Smuzhiyun * current range. Earlier ranges could also overlap,
369*4882a593Smuzhiyun * but only this one can overlap the end of the range.
370*4882a593Smuzhiyun */
371*4882a593Smuzhiyun if ((BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > target) &&
372*4882a593Smuzhiyun (BB_OFFSET(p[lo]) < target)) {
373*4882a593Smuzhiyun /* Partial overlap, leave the tail of this range */
374*4882a593Smuzhiyun int ack = BB_ACK(p[lo]);
375*4882a593Smuzhiyun sector_t a = BB_OFFSET(p[lo]);
376*4882a593Smuzhiyun sector_t end = a + BB_LEN(p[lo]);
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun if (a < s) {
379*4882a593Smuzhiyun /* we need to split this range */
380*4882a593Smuzhiyun if (bb->count >= MAX_BADBLOCKS) {
381*4882a593Smuzhiyun rv = -ENOSPC;
382*4882a593Smuzhiyun goto out;
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun memmove(p+lo+1, p+lo, (bb->count - lo) * 8);
385*4882a593Smuzhiyun bb->count++;
386*4882a593Smuzhiyun p[lo] = BB_MAKE(a, s-a, ack);
387*4882a593Smuzhiyun lo++;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun p[lo] = BB_MAKE(target, end - target, ack);
390*4882a593Smuzhiyun /* there is no longer an overlap */
391*4882a593Smuzhiyun hi = lo;
392*4882a593Smuzhiyun lo--;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun while (lo >= 0 &&
395*4882a593Smuzhiyun (BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) &&
396*4882a593Smuzhiyun (BB_OFFSET(p[lo]) < target)) {
397*4882a593Smuzhiyun /* This range does overlap */
398*4882a593Smuzhiyun if (BB_OFFSET(p[lo]) < s) {
399*4882a593Smuzhiyun /* Keep the early parts of this range. */
400*4882a593Smuzhiyun int ack = BB_ACK(p[lo]);
401*4882a593Smuzhiyun sector_t start = BB_OFFSET(p[lo]);
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun p[lo] = BB_MAKE(start, s - start, ack);
404*4882a593Smuzhiyun /* now low doesn't overlap, so.. */
405*4882a593Smuzhiyun break;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun lo--;
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun /* 'lo' is strictly before, 'hi' is strictly after,
410*4882a593Smuzhiyun * anything between needs to be discarded
411*4882a593Smuzhiyun */
412*4882a593Smuzhiyun if (hi - lo > 1) {
413*4882a593Smuzhiyun memmove(p+lo+1, p+hi, (bb->count - hi) * 8);
414*4882a593Smuzhiyun bb->count -= (hi - lo - 1);
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun badblocks_update_acked(bb);
419*4882a593Smuzhiyun bb->changed = 1;
420*4882a593Smuzhiyun out:
421*4882a593Smuzhiyun write_sequnlock_irq(&bb->lock);
422*4882a593Smuzhiyun return rv;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(badblocks_clear);
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun /**
427*4882a593Smuzhiyun * ack_all_badblocks() - Acknowledge all bad blocks in a list.
428*4882a593Smuzhiyun * @bb: the badblocks structure that holds all badblock information
429*4882a593Smuzhiyun *
430*4882a593Smuzhiyun * This only succeeds if ->changed is clear. It is used by
431*4882a593Smuzhiyun * in-kernel metadata updates
432*4882a593Smuzhiyun */
ack_all_badblocks(struct badblocks * bb)433*4882a593Smuzhiyun void ack_all_badblocks(struct badblocks *bb)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun if (bb->page == NULL || bb->changed)
436*4882a593Smuzhiyun /* no point even trying */
437*4882a593Smuzhiyun return;
438*4882a593Smuzhiyun write_seqlock_irq(&bb->lock);
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun if (bb->changed == 0 && bb->unacked_exist) {
441*4882a593Smuzhiyun u64 *p = bb->page;
442*4882a593Smuzhiyun int i;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun for (i = 0; i < bb->count ; i++) {
445*4882a593Smuzhiyun if (!BB_ACK(p[i])) {
446*4882a593Smuzhiyun sector_t start = BB_OFFSET(p[i]);
447*4882a593Smuzhiyun int len = BB_LEN(p[i]);
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun p[i] = BB_MAKE(start, len, 1);
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun bb->unacked_exist = 0;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun write_sequnlock_irq(&bb->lock);
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(ack_all_badblocks);
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun /**
459*4882a593Smuzhiyun * badblocks_show() - sysfs access to bad-blocks list
460*4882a593Smuzhiyun * @bb: the badblocks structure that holds all badblock information
461*4882a593Smuzhiyun * @page: buffer received from sysfs
462*4882a593Smuzhiyun * @unack: weather to show unacknowledged badblocks
463*4882a593Smuzhiyun *
464*4882a593Smuzhiyun * Return:
465*4882a593Smuzhiyun * Length of returned data
466*4882a593Smuzhiyun */
badblocks_show(struct badblocks * bb,char * page,int unack)467*4882a593Smuzhiyun ssize_t badblocks_show(struct badblocks *bb, char *page, int unack)
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun size_t len;
470*4882a593Smuzhiyun int i;
471*4882a593Smuzhiyun u64 *p = bb->page;
472*4882a593Smuzhiyun unsigned seq;
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun if (bb->shift < 0)
475*4882a593Smuzhiyun return 0;
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun retry:
478*4882a593Smuzhiyun seq = read_seqbegin(&bb->lock);
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun len = 0;
481*4882a593Smuzhiyun i = 0;
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun while (len < PAGE_SIZE && i < bb->count) {
484*4882a593Smuzhiyun sector_t s = BB_OFFSET(p[i]);
485*4882a593Smuzhiyun unsigned int length = BB_LEN(p[i]);
486*4882a593Smuzhiyun int ack = BB_ACK(p[i]);
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun i++;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun if (unack && ack)
491*4882a593Smuzhiyun continue;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun len += snprintf(page+len, PAGE_SIZE-len, "%llu %u\n",
494*4882a593Smuzhiyun (unsigned long long)s << bb->shift,
495*4882a593Smuzhiyun length << bb->shift);
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun if (unack && len == 0)
498*4882a593Smuzhiyun bb->unacked_exist = 0;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun if (read_seqretry(&bb->lock, seq))
501*4882a593Smuzhiyun goto retry;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun return len;
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(badblocks_show);
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun /**
508*4882a593Smuzhiyun * badblocks_store() - sysfs access to bad-blocks list
509*4882a593Smuzhiyun * @bb: the badblocks structure that holds all badblock information
510*4882a593Smuzhiyun * @page: buffer received from sysfs
511*4882a593Smuzhiyun * @len: length of data received from sysfs
512*4882a593Smuzhiyun * @unack: weather to show unacknowledged badblocks
513*4882a593Smuzhiyun *
514*4882a593Smuzhiyun * Return:
515*4882a593Smuzhiyun * Length of the buffer processed or -ve error.
516*4882a593Smuzhiyun */
badblocks_store(struct badblocks * bb,const char * page,size_t len,int unack)517*4882a593Smuzhiyun ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len,
518*4882a593Smuzhiyun int unack)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun unsigned long long sector;
521*4882a593Smuzhiyun int length;
522*4882a593Smuzhiyun char newline;
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun switch (sscanf(page, "%llu %d%c", §or, &length, &newline)) {
525*4882a593Smuzhiyun case 3:
526*4882a593Smuzhiyun if (newline != '\n')
527*4882a593Smuzhiyun return -EINVAL;
528*4882a593Smuzhiyun fallthrough;
529*4882a593Smuzhiyun case 2:
530*4882a593Smuzhiyun if (length <= 0)
531*4882a593Smuzhiyun return -EINVAL;
532*4882a593Smuzhiyun break;
533*4882a593Smuzhiyun default:
534*4882a593Smuzhiyun return -EINVAL;
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun if (badblocks_set(bb, sector, length, !unack))
538*4882a593Smuzhiyun return -ENOSPC;
539*4882a593Smuzhiyun else
540*4882a593Smuzhiyun return len;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(badblocks_store);
543*4882a593Smuzhiyun
__badblocks_init(struct device * dev,struct badblocks * bb,int enable)544*4882a593Smuzhiyun static int __badblocks_init(struct device *dev, struct badblocks *bb,
545*4882a593Smuzhiyun int enable)
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun bb->dev = dev;
548*4882a593Smuzhiyun bb->count = 0;
549*4882a593Smuzhiyun if (enable)
550*4882a593Smuzhiyun bb->shift = 0;
551*4882a593Smuzhiyun else
552*4882a593Smuzhiyun bb->shift = -1;
553*4882a593Smuzhiyun if (dev)
554*4882a593Smuzhiyun bb->page = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL);
555*4882a593Smuzhiyun else
556*4882a593Smuzhiyun bb->page = kzalloc(PAGE_SIZE, GFP_KERNEL);
557*4882a593Smuzhiyun if (!bb->page) {
558*4882a593Smuzhiyun bb->shift = -1;
559*4882a593Smuzhiyun return -ENOMEM;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun seqlock_init(&bb->lock);
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun return 0;
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun /**
567*4882a593Smuzhiyun * badblocks_init() - initialize the badblocks structure
568*4882a593Smuzhiyun * @bb: the badblocks structure that holds all badblock information
569*4882a593Smuzhiyun * @enable: weather to enable badblocks accounting
570*4882a593Smuzhiyun *
571*4882a593Smuzhiyun * Return:
572*4882a593Smuzhiyun * 0: success
573*4882a593Smuzhiyun * -ve errno: on error
574*4882a593Smuzhiyun */
badblocks_init(struct badblocks * bb,int enable)575*4882a593Smuzhiyun int badblocks_init(struct badblocks *bb, int enable)
576*4882a593Smuzhiyun {
577*4882a593Smuzhiyun return __badblocks_init(NULL, bb, enable);
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(badblocks_init);
580*4882a593Smuzhiyun
devm_init_badblocks(struct device * dev,struct badblocks * bb)581*4882a593Smuzhiyun int devm_init_badblocks(struct device *dev, struct badblocks *bb)
582*4882a593Smuzhiyun {
583*4882a593Smuzhiyun if (!bb)
584*4882a593Smuzhiyun return -EINVAL;
585*4882a593Smuzhiyun return __badblocks_init(dev, bb, 1);
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(devm_init_badblocks);
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun /**
590*4882a593Smuzhiyun * badblocks_exit() - free the badblocks structure
591*4882a593Smuzhiyun * @bb: the badblocks structure that holds all badblock information
592*4882a593Smuzhiyun */
badblocks_exit(struct badblocks * bb)593*4882a593Smuzhiyun void badblocks_exit(struct badblocks *bb)
594*4882a593Smuzhiyun {
595*4882a593Smuzhiyun if (!bb)
596*4882a593Smuzhiyun return;
597*4882a593Smuzhiyun if (bb->dev)
598*4882a593Smuzhiyun devm_kfree(bb->dev, bb->page);
599*4882a593Smuzhiyun else
600*4882a593Smuzhiyun kfree(bb->page);
601*4882a593Smuzhiyun bb->page = NULL;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(badblocks_exit);
604