xref: /openbmc/linux/block/badblocks.c (revision 3de2e5f2)
18c16567dSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0
29e0e252aSVishal Verma /*
39e0e252aSVishal Verma  * Bad block management
49e0e252aSVishal Verma  *
59e0e252aSVishal Verma  * - Heavily based on MD badblocks code from Neil Brown
69e0e252aSVishal Verma  *
79e0e252aSVishal Verma  * Copyright (c) 2015, Intel Corporation.
89e0e252aSVishal Verma  */
99e0e252aSVishal Verma 
109e0e252aSVishal Verma #include <linux/badblocks.h>
119e0e252aSVishal Verma #include <linux/seqlock.h>
1216263ff6SDan Williams #include <linux/device.h>
139e0e252aSVishal Verma #include <linux/kernel.h>
149e0e252aSVishal Verma #include <linux/module.h>
159e0e252aSVishal Verma #include <linux/stddef.h>
169e0e252aSVishal Verma #include <linux/types.h>
179e0e252aSVishal Verma #include <linux/slab.h>
189e0e252aSVishal Verma 
199e0e252aSVishal Verma /**
209e0e252aSVishal Verma  * badblocks_check() - check a given range for bad sectors
219e0e252aSVishal Verma  * @bb:		the badblocks structure that holds all badblock information
229e0e252aSVishal Verma  * @s:		sector (start) at which to check for badblocks
239e0e252aSVishal Verma  * @sectors:	number of sectors to check for badblocks
249e0e252aSVishal Verma  * @first_bad:	pointer to store location of the first badblock
259e0e252aSVishal Verma  * @bad_sectors: pointer to store number of badblocks after @first_bad
269e0e252aSVishal Verma  *
279e0e252aSVishal Verma  * We can record which blocks on each device are 'bad' and so just
289e0e252aSVishal Verma  * fail those blocks, or that stripe, rather than the whole device.
299e0e252aSVishal Verma  * Entries in the bad-block table are 64bits wide.  This comprises:
309e0e252aSVishal Verma  * Length of bad-range, in sectors: 0-511 for lengths 1-512
319e0e252aSVishal Verma  * Start of bad-range, sector offset, 54 bits (allows 8 exbibytes)
329e0e252aSVishal Verma  *  A 'shift' can be set so that larger blocks are tracked and
339e0e252aSVishal Verma  *  consequently larger devices can be covered.
349e0e252aSVishal Verma  * 'Acknowledged' flag - 1 bit. - the most significant bit.
359e0e252aSVishal Verma  *
369e0e252aSVishal Verma  * Locking of the bad-block table uses a seqlock so badblocks_check
379e0e252aSVishal Verma  * might need to retry if it is very unlucky.
389e0e252aSVishal Verma  * We will sometimes want to check for bad blocks in a bi_end_io function,
399e0e252aSVishal Verma  * so we use the write_seqlock_irq variant.
409e0e252aSVishal Verma  *
419e0e252aSVishal Verma  * When looking for a bad block we specify a range and want to
429e0e252aSVishal Verma  * know if any block in the range is bad.  So we binary-search
439e0e252aSVishal Verma  * to the last range that starts at-or-before the given endpoint,
449e0e252aSVishal Verma  * (or "before the sector after the target range")
459e0e252aSVishal Verma  * then see if it ends after the given start.
469e0e252aSVishal Verma  *
479e0e252aSVishal Verma  * Return:
489e0e252aSVishal Verma  *  0: there are no known bad blocks in the range
499e0e252aSVishal Verma  *  1: there are known bad block which are all acknowledged
509e0e252aSVishal Verma  * -1: there are bad blocks which have not yet been acknowledged in metadata.
519e0e252aSVishal Verma  * plus the start/length of the first bad section we overlap.
529e0e252aSVishal Verma  */
badblocks_check(struct badblocks * bb,sector_t s,int sectors,sector_t * first_bad,int * bad_sectors)539e0e252aSVishal Verma int badblocks_check(struct badblocks *bb, sector_t s, int sectors,
549e0e252aSVishal Verma 			sector_t *first_bad, int *bad_sectors)
559e0e252aSVishal Verma {
569e0e252aSVishal Verma 	int hi;
579e0e252aSVishal Verma 	int lo;
589e0e252aSVishal Verma 	u64 *p = bb->page;
599e0e252aSVishal Verma 	int rv;
609e0e252aSVishal Verma 	sector_t target = s + sectors;
619e0e252aSVishal Verma 	unsigned seq;
629e0e252aSVishal Verma 
639e0e252aSVishal Verma 	if (bb->shift > 0) {
649e0e252aSVishal Verma 		/* round the start down, and the end up */
659e0e252aSVishal Verma 		s >>= bb->shift;
669e0e252aSVishal Verma 		target += (1<<bb->shift) - 1;
679e0e252aSVishal Verma 		target >>= bb->shift;
689e0e252aSVishal Verma 	}
699e0e252aSVishal Verma 	/* 'target' is now the first block after the bad range */
709e0e252aSVishal Verma 
719e0e252aSVishal Verma retry:
729e0e252aSVishal Verma 	seq = read_seqbegin(&bb->lock);
739e0e252aSVishal Verma 	lo = 0;
749e0e252aSVishal Verma 	rv = 0;
759e0e252aSVishal Verma 	hi = bb->count;
769e0e252aSVishal Verma 
779e0e252aSVishal Verma 	/* Binary search between lo and hi for 'target'
789e0e252aSVishal Verma 	 * i.e. for the last range that starts before 'target'
799e0e252aSVishal Verma 	 */
809e0e252aSVishal Verma 	/* INVARIANT: ranges before 'lo' and at-or-after 'hi'
819e0e252aSVishal Verma 	 * are known not to be the last range before target.
829e0e252aSVishal Verma 	 * VARIANT: hi-lo is the number of possible
839e0e252aSVishal Verma 	 * ranges, and decreases until it reaches 1
849e0e252aSVishal Verma 	 */
859e0e252aSVishal Verma 	while (hi - lo > 1) {
869e0e252aSVishal Verma 		int mid = (lo + hi) / 2;
879e0e252aSVishal Verma 		sector_t a = BB_OFFSET(p[mid]);
889e0e252aSVishal Verma 
899e0e252aSVishal Verma 		if (a < target)
909e0e252aSVishal Verma 			/* This could still be the one, earlier ranges
919e0e252aSVishal Verma 			 * could not.
929e0e252aSVishal Verma 			 */
939e0e252aSVishal Verma 			lo = mid;
949e0e252aSVishal Verma 		else
959e0e252aSVishal Verma 			/* This and later ranges are definitely out. */
969e0e252aSVishal Verma 			hi = mid;
979e0e252aSVishal Verma 	}
989e0e252aSVishal Verma 	/* 'lo' might be the last that started before target, but 'hi' isn't */
999e0e252aSVishal Verma 	if (hi > lo) {
1009e0e252aSVishal Verma 		/* need to check all range that end after 's' to see if
1019e0e252aSVishal Verma 		 * any are unacknowledged.
1029e0e252aSVishal Verma 		 */
1039e0e252aSVishal Verma 		while (lo >= 0 &&
1049e0e252aSVishal Verma 		       BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) {
1059e0e252aSVishal Verma 			if (BB_OFFSET(p[lo]) < target) {
1069e0e252aSVishal Verma 				/* starts before the end, and finishes after
1079e0e252aSVishal Verma 				 * the start, so they must overlap
1089e0e252aSVishal Verma 				 */
1099e0e252aSVishal Verma 				if (rv != -1 && BB_ACK(p[lo]))
1109e0e252aSVishal Verma 					rv = 1;
1119e0e252aSVishal Verma 				else
1129e0e252aSVishal Verma 					rv = -1;
1139e0e252aSVishal Verma 				*first_bad = BB_OFFSET(p[lo]);
1149e0e252aSVishal Verma 				*bad_sectors = BB_LEN(p[lo]);
1159e0e252aSVishal Verma 			}
1169e0e252aSVishal Verma 			lo--;
1179e0e252aSVishal Verma 		}
1189e0e252aSVishal Verma 	}
1199e0e252aSVishal Verma 
1209e0e252aSVishal Verma 	if (read_seqretry(&bb->lock, seq))
1219e0e252aSVishal Verma 		goto retry;
1229e0e252aSVishal Verma 
1239e0e252aSVishal Verma 	return rv;
1249e0e252aSVishal Verma }
1259e0e252aSVishal Verma EXPORT_SYMBOL_GPL(badblocks_check);
1269e0e252aSVishal Verma 
badblocks_update_acked(struct badblocks * bb)127b4a1278cSShaohua Li static void badblocks_update_acked(struct badblocks *bb)
128b4a1278cSShaohua Li {
129b4a1278cSShaohua Li 	u64 *p = bb->page;
130b4a1278cSShaohua Li 	int i;
131b4a1278cSShaohua Li 	bool unacked = false;
132b4a1278cSShaohua Li 
133b4a1278cSShaohua Li 	if (!bb->unacked_exist)
134b4a1278cSShaohua Li 		return;
135b4a1278cSShaohua Li 
136b4a1278cSShaohua Li 	for (i = 0; i < bb->count ; i++) {
137b4a1278cSShaohua Li 		if (!BB_ACK(p[i])) {
138b4a1278cSShaohua Li 			unacked = true;
139b4a1278cSShaohua Li 			break;
140b4a1278cSShaohua Li 		}
141b4a1278cSShaohua Li 	}
142b4a1278cSShaohua Li 
143b4a1278cSShaohua Li 	if (!unacked)
144b4a1278cSShaohua Li 		bb->unacked_exist = 0;
145b4a1278cSShaohua Li }
146b4a1278cSShaohua Li 
1479e0e252aSVishal Verma /**
1489e0e252aSVishal Verma  * badblocks_set() - Add a range of bad blocks to the table.
1499e0e252aSVishal Verma  * @bb:		the badblocks structure that holds all badblock information
1509e0e252aSVishal Verma  * @s:		first sector to mark as bad
1519e0e252aSVishal Verma  * @sectors:	number of sectors to mark as bad
1529e0e252aSVishal Verma  * @acknowledged: weather to mark the bad sectors as acknowledged
1539e0e252aSVishal Verma  *
1549e0e252aSVishal Verma  * This might extend the table, or might contract it if two adjacent ranges
1559e0e252aSVishal Verma  * can be merged. We binary-search to find the 'insertion' point, then
1569e0e252aSVishal Verma  * decide how best to handle it.
1579e0e252aSVishal Verma  *
1589e0e252aSVishal Verma  * Return:
1599e0e252aSVishal Verma  *  0: success
1609e0e252aSVishal Verma  *  1: failed to set badblocks (out of space)
1619e0e252aSVishal Verma  */
badblocks_set(struct badblocks * bb,sector_t s,int sectors,int acknowledged)1629e0e252aSVishal Verma int badblocks_set(struct badblocks *bb, sector_t s, int sectors,
1639e0e252aSVishal Verma 			int acknowledged)
1649e0e252aSVishal Verma {
1659e0e252aSVishal Verma 	u64 *p;
1669e0e252aSVishal Verma 	int lo, hi;
1679e0e252aSVishal Verma 	int rv = 0;
1689e0e252aSVishal Verma 	unsigned long flags;
1699e0e252aSVishal Verma 
1709e0e252aSVishal Verma 	if (bb->shift < 0)
1719e0e252aSVishal Verma 		/* badblocks are disabled */
17239b4954cSLiu Bo 		return 1;
1739e0e252aSVishal Verma 
1749e0e252aSVishal Verma 	if (bb->shift) {
1759e0e252aSVishal Verma 		/* round the start down, and the end up */
1769e0e252aSVishal Verma 		sector_t next = s + sectors;
1779e0e252aSVishal Verma 
1789e0e252aSVishal Verma 		s >>= bb->shift;
1799e0e252aSVishal Verma 		next += (1<<bb->shift) - 1;
1809e0e252aSVishal Verma 		next >>= bb->shift;
1819e0e252aSVishal Verma 		sectors = next - s;
1829e0e252aSVishal Verma 	}
1839e0e252aSVishal Verma 
1849e0e252aSVishal Verma 	write_seqlock_irqsave(&bb->lock, flags);
1859e0e252aSVishal Verma 
1869e0e252aSVishal Verma 	p = bb->page;
1879e0e252aSVishal Verma 	lo = 0;
1889e0e252aSVishal Verma 	hi = bb->count;
1899e0e252aSVishal Verma 	/* Find the last range that starts at-or-before 's' */
1909e0e252aSVishal Verma 	while (hi - lo > 1) {
1919e0e252aSVishal Verma 		int mid = (lo + hi) / 2;
1929e0e252aSVishal Verma 		sector_t a = BB_OFFSET(p[mid]);
1939e0e252aSVishal Verma 
1949e0e252aSVishal Verma 		if (a <= s)
1959e0e252aSVishal Verma 			lo = mid;
1969e0e252aSVishal Verma 		else
1979e0e252aSVishal Verma 			hi = mid;
1989e0e252aSVishal Verma 	}
1999e0e252aSVishal Verma 	if (hi > lo && BB_OFFSET(p[lo]) > s)
2009e0e252aSVishal Verma 		hi = lo;
2019e0e252aSVishal Verma 
2029e0e252aSVishal Verma 	if (hi > lo) {
2039e0e252aSVishal Verma 		/* we found a range that might merge with the start
2049e0e252aSVishal Verma 		 * of our new range
2059e0e252aSVishal Verma 		 */
2069e0e252aSVishal Verma 		sector_t a = BB_OFFSET(p[lo]);
2079e0e252aSVishal Verma 		sector_t e = a + BB_LEN(p[lo]);
2089e0e252aSVishal Verma 		int ack = BB_ACK(p[lo]);
2099e0e252aSVishal Verma 
2109e0e252aSVishal Verma 		if (e >= s) {
2119e0e252aSVishal Verma 			/* Yes, we can merge with a previous range */
2129e0e252aSVishal Verma 			if (s == a && s + sectors >= e)
2139e0e252aSVishal Verma 				/* new range covers old */
2149e0e252aSVishal Verma 				ack = acknowledged;
2159e0e252aSVishal Verma 			else
2169e0e252aSVishal Verma 				ack = ack && acknowledged;
2179e0e252aSVishal Verma 
2189e0e252aSVishal Verma 			if (e < s + sectors)
2199e0e252aSVishal Verma 				e = s + sectors;
2209e0e252aSVishal Verma 			if (e - a <= BB_MAX_LEN) {
2219e0e252aSVishal Verma 				p[lo] = BB_MAKE(a, e-a, ack);
2229e0e252aSVishal Verma 				s = e;
2239e0e252aSVishal Verma 			} else {
2249e0e252aSVishal Verma 				/* does not all fit in one range,
2259e0e252aSVishal Verma 				 * make p[lo] maximal
2269e0e252aSVishal Verma 				 */
2279e0e252aSVishal Verma 				if (BB_LEN(p[lo]) != BB_MAX_LEN)
2289e0e252aSVishal Verma 					p[lo] = BB_MAKE(a, BB_MAX_LEN, ack);
2299e0e252aSVishal Verma 				s = a + BB_MAX_LEN;
2309e0e252aSVishal Verma 			}
2319e0e252aSVishal Verma 			sectors = e - s;
2329e0e252aSVishal Verma 		}
2339e0e252aSVishal Verma 	}
2349e0e252aSVishal Verma 	if (sectors && hi < bb->count) {
2359e0e252aSVishal Verma 		/* 'hi' points to the first range that starts after 's'.
2369e0e252aSVishal Verma 		 * Maybe we can merge with the start of that range
2379e0e252aSVishal Verma 		 */
2389e0e252aSVishal Verma 		sector_t a = BB_OFFSET(p[hi]);
2399e0e252aSVishal Verma 		sector_t e = a + BB_LEN(p[hi]);
2409e0e252aSVishal Verma 		int ack = BB_ACK(p[hi]);
2419e0e252aSVishal Verma 
2429e0e252aSVishal Verma 		if (a <= s + sectors) {
2439e0e252aSVishal Verma 			/* merging is possible */
2449e0e252aSVishal Verma 			if (e <= s + sectors) {
2459e0e252aSVishal Verma 				/* full overlap */
2469e0e252aSVishal Verma 				e = s + sectors;
2479e0e252aSVishal Verma 				ack = acknowledged;
2489e0e252aSVishal Verma 			} else
2499e0e252aSVishal Verma 				ack = ack && acknowledged;
2509e0e252aSVishal Verma 
2519e0e252aSVishal Verma 			a = s;
2529e0e252aSVishal Verma 			if (e - a <= BB_MAX_LEN) {
2539e0e252aSVishal Verma 				p[hi] = BB_MAKE(a, e-a, ack);
2549e0e252aSVishal Verma 				s = e;
2559e0e252aSVishal Verma 			} else {
2569e0e252aSVishal Verma 				p[hi] = BB_MAKE(a, BB_MAX_LEN, ack);
2579e0e252aSVishal Verma 				s = a + BB_MAX_LEN;
2589e0e252aSVishal Verma 			}
2599e0e252aSVishal Verma 			sectors = e - s;
2609e0e252aSVishal Verma 			lo = hi;
2619e0e252aSVishal Verma 			hi++;
2629e0e252aSVishal Verma 		}
2639e0e252aSVishal Verma 	}
2649e0e252aSVishal Verma 	if (sectors == 0 && hi < bb->count) {
2659e0e252aSVishal Verma 		/* we might be able to combine lo and hi */
2669e0e252aSVishal Verma 		/* Note: 's' is at the end of 'lo' */
2679e0e252aSVishal Verma 		sector_t a = BB_OFFSET(p[hi]);
2689e0e252aSVishal Verma 		int lolen = BB_LEN(p[lo]);
2699e0e252aSVishal Verma 		int hilen = BB_LEN(p[hi]);
2709e0e252aSVishal Verma 		int newlen = lolen + hilen - (s - a);
2719e0e252aSVishal Verma 
2729e0e252aSVishal Verma 		if (s >= a && newlen < BB_MAX_LEN) {
2739e0e252aSVishal Verma 			/* yes, we can combine them */
2749e0e252aSVishal Verma 			int ack = BB_ACK(p[lo]) && BB_ACK(p[hi]);
2759e0e252aSVishal Verma 
2769e0e252aSVishal Verma 			p[lo] = BB_MAKE(BB_OFFSET(p[lo]), newlen, ack);
2779e0e252aSVishal Verma 			memmove(p + hi, p + hi + 1,
2789e0e252aSVishal Verma 				(bb->count - hi - 1) * 8);
2799e0e252aSVishal Verma 			bb->count--;
2809e0e252aSVishal Verma 		}
2819e0e252aSVishal Verma 	}
2829e0e252aSVishal Verma 	while (sectors) {
2839e0e252aSVishal Verma 		/* didn't merge (it all).
2849e0e252aSVishal Verma 		 * Need to add a range just before 'hi'
2859e0e252aSVishal Verma 		 */
2869e0e252aSVishal Verma 		if (bb->count >= MAX_BADBLOCKS) {
2879e0e252aSVishal Verma 			/* No room for more */
2889e0e252aSVishal Verma 			rv = 1;
2899e0e252aSVishal Verma 			break;
2909e0e252aSVishal Verma 		} else {
2919e0e252aSVishal Verma 			int this_sectors = sectors;
2929e0e252aSVishal Verma 
2939e0e252aSVishal Verma 			memmove(p + hi + 1, p + hi,
2949e0e252aSVishal Verma 				(bb->count - hi) * 8);
2959e0e252aSVishal Verma 			bb->count++;
2969e0e252aSVishal Verma 
2979e0e252aSVishal Verma 			if (this_sectors > BB_MAX_LEN)
2989e0e252aSVishal Verma 				this_sectors = BB_MAX_LEN;
2999e0e252aSVishal Verma 			p[hi] = BB_MAKE(s, this_sectors, acknowledged);
3009e0e252aSVishal Verma 			sectors -= this_sectors;
3019e0e252aSVishal Verma 			s += this_sectors;
3029e0e252aSVishal Verma 		}
3039e0e252aSVishal Verma 	}
3049e0e252aSVishal Verma 
3059e0e252aSVishal Verma 	bb->changed = 1;
3069e0e252aSVishal Verma 	if (!acknowledged)
3079e0e252aSVishal Verma 		bb->unacked_exist = 1;
308b4a1278cSShaohua Li 	else
309b4a1278cSShaohua Li 		badblocks_update_acked(bb);
3109e0e252aSVishal Verma 	write_sequnlock_irqrestore(&bb->lock, flags);
3119e0e252aSVishal Verma 
3129e0e252aSVishal Verma 	return rv;
3139e0e252aSVishal Verma }
3149e0e252aSVishal Verma EXPORT_SYMBOL_GPL(badblocks_set);
3159e0e252aSVishal Verma 
3169e0e252aSVishal Verma /**
3179e0e252aSVishal Verma  * badblocks_clear() - Remove a range of bad blocks to the table.
3189e0e252aSVishal Verma  * @bb:		the badblocks structure that holds all badblock information
3199e0e252aSVishal Verma  * @s:		first sector to mark as bad
3209e0e252aSVishal Verma  * @sectors:	number of sectors to mark as bad
3219e0e252aSVishal Verma  *
3229e0e252aSVishal Verma  * This may involve extending the table if we spilt a region,
3239e0e252aSVishal Verma  * but it must not fail.  So if the table becomes full, we just
3249e0e252aSVishal Verma  * drop the remove request.
3259e0e252aSVishal Verma  *
3269e0e252aSVishal Verma  * Return:
3279e0e252aSVishal Verma  *  0: success
3289e0e252aSVishal Verma  *  1: failed to clear badblocks
3299e0e252aSVishal Verma  */
badblocks_clear(struct badblocks * bb,sector_t s,int sectors)3309e0e252aSVishal Verma int badblocks_clear(struct badblocks *bb, sector_t s, int sectors)
3319e0e252aSVishal Verma {
3329e0e252aSVishal Verma 	u64 *p;
3339e0e252aSVishal Verma 	int lo, hi;
3349e0e252aSVishal Verma 	sector_t target = s + sectors;
3359e0e252aSVishal Verma 	int rv = 0;
3369e0e252aSVishal Verma 
3379e0e252aSVishal Verma 	if (bb->shift > 0) {
3389e0e252aSVishal Verma 		/* When clearing we round the start up and the end down.
3399e0e252aSVishal Verma 		 * This should not matter as the shift should align with
3409e0e252aSVishal Verma 		 * the block size and no rounding should ever be needed.
3419e0e252aSVishal Verma 		 * However it is better the think a block is bad when it
3429e0e252aSVishal Verma 		 * isn't than to think a block is not bad when it is.
3439e0e252aSVishal Verma 		 */
3449e0e252aSVishal Verma 		s += (1<<bb->shift) - 1;
3459e0e252aSVishal Verma 		s >>= bb->shift;
3469e0e252aSVishal Verma 		target >>= bb->shift;
3479e0e252aSVishal Verma 	}
3489e0e252aSVishal Verma 
3499e0e252aSVishal Verma 	write_seqlock_irq(&bb->lock);
3509e0e252aSVishal Verma 
3519e0e252aSVishal Verma 	p = bb->page;
3529e0e252aSVishal Verma 	lo = 0;
3539e0e252aSVishal Verma 	hi = bb->count;
3549e0e252aSVishal Verma 	/* Find the last range that starts before 'target' */
3559e0e252aSVishal Verma 	while (hi - lo > 1) {
3569e0e252aSVishal Verma 		int mid = (lo + hi) / 2;
3579e0e252aSVishal Verma 		sector_t a = BB_OFFSET(p[mid]);
3589e0e252aSVishal Verma 
3599e0e252aSVishal Verma 		if (a < target)
3609e0e252aSVishal Verma 			lo = mid;
3619e0e252aSVishal Verma 		else
3629e0e252aSVishal Verma 			hi = mid;
3639e0e252aSVishal Verma 	}
3649e0e252aSVishal Verma 	if (hi > lo) {
3659e0e252aSVishal Verma 		/* p[lo] is the last range that could overlap the
3669e0e252aSVishal Verma 		 * current range.  Earlier ranges could also overlap,
3679e0e252aSVishal Verma 		 * but only this one can overlap the end of the range.
3689e0e252aSVishal Verma 		 */
3691fa9ce8dSTomasz Majchrzak 		if ((BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > target) &&
3701fa9ce8dSTomasz Majchrzak 		    (BB_OFFSET(p[lo]) < target)) {
3719e0e252aSVishal Verma 			/* Partial overlap, leave the tail of this range */
3729e0e252aSVishal Verma 			int ack = BB_ACK(p[lo]);
3739e0e252aSVishal Verma 			sector_t a = BB_OFFSET(p[lo]);
3749e0e252aSVishal Verma 			sector_t end = a + BB_LEN(p[lo]);
3759e0e252aSVishal Verma 
3769e0e252aSVishal Verma 			if (a < s) {
3779e0e252aSVishal Verma 				/* we need to split this range */
3789e0e252aSVishal Verma 				if (bb->count >= MAX_BADBLOCKS) {
3799e0e252aSVishal Verma 					rv = -ENOSPC;
3809e0e252aSVishal Verma 					goto out;
3819e0e252aSVishal Verma 				}
3829e0e252aSVishal Verma 				memmove(p+lo+1, p+lo, (bb->count - lo) * 8);
3839e0e252aSVishal Verma 				bb->count++;
3849e0e252aSVishal Verma 				p[lo] = BB_MAKE(a, s-a, ack);
3859e0e252aSVishal Verma 				lo++;
3869e0e252aSVishal Verma 			}
3879e0e252aSVishal Verma 			p[lo] = BB_MAKE(target, end - target, ack);
3889e0e252aSVishal Verma 			/* there is no longer an overlap */
3899e0e252aSVishal Verma 			hi = lo;
3909e0e252aSVishal Verma 			lo--;
3919e0e252aSVishal Verma 		}
3929e0e252aSVishal Verma 		while (lo >= 0 &&
3931fa9ce8dSTomasz Majchrzak 		       (BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) &&
3941fa9ce8dSTomasz Majchrzak 		       (BB_OFFSET(p[lo]) < target)) {
3959e0e252aSVishal Verma 			/* This range does overlap */
3969e0e252aSVishal Verma 			if (BB_OFFSET(p[lo]) < s) {
3979e0e252aSVishal Verma 				/* Keep the early parts of this range. */
3989e0e252aSVishal Verma 				int ack = BB_ACK(p[lo]);
3999e0e252aSVishal Verma 				sector_t start = BB_OFFSET(p[lo]);
4009e0e252aSVishal Verma 
4019e0e252aSVishal Verma 				p[lo] = BB_MAKE(start, s - start, ack);
4029e0e252aSVishal Verma 				/* now low doesn't overlap, so.. */
4039e0e252aSVishal Verma 				break;
4049e0e252aSVishal Verma 			}
4059e0e252aSVishal Verma 			lo--;
4069e0e252aSVishal Verma 		}
4079e0e252aSVishal Verma 		/* 'lo' is strictly before, 'hi' is strictly after,
4089e0e252aSVishal Verma 		 * anything between needs to be discarded
4099e0e252aSVishal Verma 		 */
4109e0e252aSVishal Verma 		if (hi - lo > 1) {
4119e0e252aSVishal Verma 			memmove(p+lo+1, p+hi, (bb->count - hi) * 8);
4129e0e252aSVishal Verma 			bb->count -= (hi - lo - 1);
4139e0e252aSVishal Verma 		}
4149e0e252aSVishal Verma 	}
4159e0e252aSVishal Verma 
416b4a1278cSShaohua Li 	badblocks_update_acked(bb);
4179e0e252aSVishal Verma 	bb->changed = 1;
4189e0e252aSVishal Verma out:
4199e0e252aSVishal Verma 	write_sequnlock_irq(&bb->lock);
4209e0e252aSVishal Verma 	return rv;
4219e0e252aSVishal Verma }
4229e0e252aSVishal Verma EXPORT_SYMBOL_GPL(badblocks_clear);
4239e0e252aSVishal Verma 
4249e0e252aSVishal Verma /**
4259e0e252aSVishal Verma  * ack_all_badblocks() - Acknowledge all bad blocks in a list.
4269e0e252aSVishal Verma  * @bb:		the badblocks structure that holds all badblock information
4279e0e252aSVishal Verma  *
4289e0e252aSVishal Verma  * This only succeeds if ->changed is clear.  It is used by
4299e0e252aSVishal Verma  * in-kernel metadata updates
4309e0e252aSVishal Verma  */
ack_all_badblocks(struct badblocks * bb)4319e0e252aSVishal Verma void ack_all_badblocks(struct badblocks *bb)
4329e0e252aSVishal Verma {
4339e0e252aSVishal Verma 	if (bb->page == NULL || bb->changed)
4349e0e252aSVishal Verma 		/* no point even trying */
4359e0e252aSVishal Verma 		return;
4369e0e252aSVishal Verma 	write_seqlock_irq(&bb->lock);
4379e0e252aSVishal Verma 
4389e0e252aSVishal Verma 	if (bb->changed == 0 && bb->unacked_exist) {
4399e0e252aSVishal Verma 		u64 *p = bb->page;
4409e0e252aSVishal Verma 		int i;
4419e0e252aSVishal Verma 
4429e0e252aSVishal Verma 		for (i = 0; i < bb->count ; i++) {
4439e0e252aSVishal Verma 			if (!BB_ACK(p[i])) {
4449e0e252aSVishal Verma 				sector_t start = BB_OFFSET(p[i]);
4459e0e252aSVishal Verma 				int len = BB_LEN(p[i]);
4469e0e252aSVishal Verma 
4479e0e252aSVishal Verma 				p[i] = BB_MAKE(start, len, 1);
4489e0e252aSVishal Verma 			}
4499e0e252aSVishal Verma 		}
4509e0e252aSVishal Verma 		bb->unacked_exist = 0;
4519e0e252aSVishal Verma 	}
4529e0e252aSVishal Verma 	write_sequnlock_irq(&bb->lock);
4539e0e252aSVishal Verma }
4549e0e252aSVishal Verma EXPORT_SYMBOL_GPL(ack_all_badblocks);
4559e0e252aSVishal Verma 
4569e0e252aSVishal Verma /**
4579e0e252aSVishal Verma  * badblocks_show() - sysfs access to bad-blocks list
4589e0e252aSVishal Verma  * @bb:		the badblocks structure that holds all badblock information
4599e0e252aSVishal Verma  * @page:	buffer received from sysfs
4609e0e252aSVishal Verma  * @unack:	weather to show unacknowledged badblocks
4619e0e252aSVishal Verma  *
4629e0e252aSVishal Verma  * Return:
4639e0e252aSVishal Verma  *  Length of returned data
4649e0e252aSVishal Verma  */
badblocks_show(struct badblocks * bb,char * page,int unack)4659e0e252aSVishal Verma ssize_t badblocks_show(struct badblocks *bb, char *page, int unack)
4669e0e252aSVishal Verma {
4679e0e252aSVishal Verma 	size_t len;
4689e0e252aSVishal Verma 	int i;
4699e0e252aSVishal Verma 	u64 *p = bb->page;
4709e0e252aSVishal Verma 	unsigned seq;
4719e0e252aSVishal Verma 
4729e0e252aSVishal Verma 	if (bb->shift < 0)
4739e0e252aSVishal Verma 		return 0;
4749e0e252aSVishal Verma 
4759e0e252aSVishal Verma retry:
4769e0e252aSVishal Verma 	seq = read_seqbegin(&bb->lock);
4779e0e252aSVishal Verma 
4789e0e252aSVishal Verma 	len = 0;
4799e0e252aSVishal Verma 	i = 0;
4809e0e252aSVishal Verma 
4819e0e252aSVishal Verma 	while (len < PAGE_SIZE && i < bb->count) {
4829e0e252aSVishal Verma 		sector_t s = BB_OFFSET(p[i]);
4839e0e252aSVishal Verma 		unsigned int length = BB_LEN(p[i]);
4849e0e252aSVishal Verma 		int ack = BB_ACK(p[i]);
4859e0e252aSVishal Verma 
4869e0e252aSVishal Verma 		i++;
4879e0e252aSVishal Verma 
4889e0e252aSVishal Verma 		if (unack && ack)
4899e0e252aSVishal Verma 			continue;
4909e0e252aSVishal Verma 
4919e0e252aSVishal Verma 		len += snprintf(page+len, PAGE_SIZE-len, "%llu %u\n",
4929e0e252aSVishal Verma 				(unsigned long long)s << bb->shift,
4939e0e252aSVishal Verma 				length << bb->shift);
4949e0e252aSVishal Verma 	}
4959e0e252aSVishal Verma 	if (unack && len == 0)
4969e0e252aSVishal Verma 		bb->unacked_exist = 0;
4979e0e252aSVishal Verma 
4989e0e252aSVishal Verma 	if (read_seqretry(&bb->lock, seq))
4999e0e252aSVishal Verma 		goto retry;
5009e0e252aSVishal Verma 
5019e0e252aSVishal Verma 	return len;
5029e0e252aSVishal Verma }
5039e0e252aSVishal Verma EXPORT_SYMBOL_GPL(badblocks_show);
5049e0e252aSVishal Verma 
5059e0e252aSVishal Verma /**
5069e0e252aSVishal Verma  * badblocks_store() - sysfs access to bad-blocks list
5079e0e252aSVishal Verma  * @bb:		the badblocks structure that holds all badblock information
5089e0e252aSVishal Verma  * @page:	buffer received from sysfs
5099e0e252aSVishal Verma  * @len:	length of data received from sysfs
5109e0e252aSVishal Verma  * @unack:	weather to show unacknowledged badblocks
5119e0e252aSVishal Verma  *
5129e0e252aSVishal Verma  * Return:
5139e0e252aSVishal Verma  *  Length of the buffer processed or -ve error.
5149e0e252aSVishal Verma  */
badblocks_store(struct badblocks * bb,const char * page,size_t len,int unack)5159e0e252aSVishal Verma ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len,
5169e0e252aSVishal Verma 			int unack)
5179e0e252aSVishal Verma {
5189e0e252aSVishal Verma 	unsigned long long sector;
5199e0e252aSVishal Verma 	int length;
5209e0e252aSVishal Verma 	char newline;
5219e0e252aSVishal Verma 
5229e0e252aSVishal Verma 	switch (sscanf(page, "%llu %d%c", &sector, &length, &newline)) {
5239e0e252aSVishal Verma 	case 3:
5249e0e252aSVishal Verma 		if (newline != '\n')
5259e0e252aSVishal Verma 			return -EINVAL;
526df561f66SGustavo A. R. Silva 		fallthrough;
5279e0e252aSVishal Verma 	case 2:
5289e0e252aSVishal Verma 		if (length <= 0)
5299e0e252aSVishal Verma 			return -EINVAL;
5309e0e252aSVishal Verma 		break;
5319e0e252aSVishal Verma 	default:
5329e0e252aSVishal Verma 		return -EINVAL;
5339e0e252aSVishal Verma 	}
5349e0e252aSVishal Verma 
5359e0e252aSVishal Verma 	if (badblocks_set(bb, sector, length, !unack))
5369e0e252aSVishal Verma 		return -ENOSPC;
5379e0e252aSVishal Verma 	else
5389e0e252aSVishal Verma 		return len;
5399e0e252aSVishal Verma }
5409e0e252aSVishal Verma EXPORT_SYMBOL_GPL(badblocks_store);
5419e0e252aSVishal Verma 
__badblocks_init(struct device * dev,struct badblocks * bb,int enable)54216263ff6SDan Williams static int __badblocks_init(struct device *dev, struct badblocks *bb,
54316263ff6SDan Williams 		int enable)
54416263ff6SDan Williams {
54516263ff6SDan Williams 	bb->dev = dev;
54616263ff6SDan Williams 	bb->count = 0;
54716263ff6SDan Williams 	if (enable)
54816263ff6SDan Williams 		bb->shift = 0;
54916263ff6SDan Williams 	else
55016263ff6SDan Williams 		bb->shift = -1;
55116263ff6SDan Williams 	if (dev)
55216263ff6SDan Williams 		bb->page = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL);
55316263ff6SDan Williams 	else
55416263ff6SDan Williams 		bb->page = kzalloc(PAGE_SIZE, GFP_KERNEL);
55516263ff6SDan Williams 	if (!bb->page) {
55616263ff6SDan Williams 		bb->shift = -1;
55716263ff6SDan Williams 		return -ENOMEM;
55816263ff6SDan Williams 	}
55916263ff6SDan Williams 	seqlock_init(&bb->lock);
56016263ff6SDan Williams 
56116263ff6SDan Williams 	return 0;
56216263ff6SDan Williams }
56316263ff6SDan Williams 
5649e0e252aSVishal Verma /**
5659e0e252aSVishal Verma  * badblocks_init() - initialize the badblocks structure
5669e0e252aSVishal Verma  * @bb:		the badblocks structure that holds all badblock information
5679e0e252aSVishal Verma  * @enable:	weather to enable badblocks accounting
5689e0e252aSVishal Verma  *
5699e0e252aSVishal Verma  * Return:
5709e0e252aSVishal Verma  *  0: success
5719e0e252aSVishal Verma  *  -ve errno: on error
5729e0e252aSVishal Verma  */
badblocks_init(struct badblocks * bb,int enable)5739e0e252aSVishal Verma int badblocks_init(struct badblocks *bb, int enable)
5749e0e252aSVishal Verma {
57516263ff6SDan Williams 	return __badblocks_init(NULL, bb, enable);
5769e0e252aSVishal Verma }
5779e0e252aSVishal Verma EXPORT_SYMBOL_GPL(badblocks_init);
5789e0e252aSVishal Verma 
devm_init_badblocks(struct device * dev,struct badblocks * bb)57916263ff6SDan Williams int devm_init_badblocks(struct device *dev, struct badblocks *bb)
58016263ff6SDan Williams {
58116263ff6SDan Williams 	if (!bb)
58216263ff6SDan Williams 		return -EINVAL;
58316263ff6SDan Williams 	return __badblocks_init(dev, bb, 1);
58416263ff6SDan Williams }
58516263ff6SDan Williams EXPORT_SYMBOL_GPL(devm_init_badblocks);
58616263ff6SDan Williams 
5879e0e252aSVishal Verma /**
588d3b407fbSDan Williams  * badblocks_exit() - free the badblocks structure
5899e0e252aSVishal Verma  * @bb:		the badblocks structure that holds all badblock information
5909e0e252aSVishal Verma  */
badblocks_exit(struct badblocks * bb)591d3b407fbSDan Williams void badblocks_exit(struct badblocks *bb)
5929e0e252aSVishal Verma {
59320a308f0SDan Williams 	if (!bb)
59420a308f0SDan Williams 		return;
59516263ff6SDan Williams 	if (bb->dev)
59616263ff6SDan Williams 		devm_kfree(bb->dev, bb->page);
59716263ff6SDan Williams 	else
5989e0e252aSVishal Verma 		kfree(bb->page);
5999e0e252aSVishal Verma 	bb->page = NULL;
6009e0e252aSVishal Verma }
601d3b407fbSDan Williams EXPORT_SYMBOL_GPL(badblocks_exit);
602