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