Lines Matching full:bb
457 static int prev_by_hint(struct badblocks *bb, sector_t s, int hint) in prev_by_hint() argument
460 u64 *p = bb->page; in prev_by_hint()
463 while ((hint < hint_end) && ((hint + 1) <= bb->count) && in prev_by_hint()
465 if ((hint + 1) == bb->count || BB_OFFSET(p[hint + 1]) > s) { in prev_by_hint()
481 static int prev_badblocks(struct badblocks *bb, struct badblocks_context *bad, in prev_badblocks() argument
489 if (!bb->count) in prev_badblocks()
493 ret = prev_by_hint(bb, s, hint); in prev_badblocks()
499 hi = bb->count; in prev_badblocks()
500 p = bb->page; in prev_badblocks()
534 static bool can_merge_front(struct badblocks *bb, int prev, in can_merge_front() argument
538 u64 *p = bb->page; in can_merge_front()
552 static int front_merge(struct badblocks *bb, int prev, struct badblocks_context *bad) in front_merge() argument
556 u64 *p = bb->page; in front_merge()
565 if ((prev + 1) < bb->count && in front_merge()
588 static bool can_combine_front(struct badblocks *bb, int prev, in can_combine_front() argument
591 u64 *p = bb->page; in can_combine_front()
606 * The caller of front_combine() will decrease bb->count, therefore
609 static void front_combine(struct badblocks *bb, int prev) in front_combine() argument
611 u64 *p = bb->page; in front_combine()
616 if ((prev + 1) < bb->count) in front_combine()
617 memmove(p + prev, p + prev + 1, (bb->count - prev - 1) * 8); in front_combine()
626 static bool overlap_front(struct badblocks *bb, int front, in overlap_front() argument
629 u64 *p = bb->page; in overlap_front()
641 static bool overlap_behind(struct badblocks *bb, struct badblocks_context *bad, in overlap_behind() argument
644 u64 *p = bb->page; in overlap_behind()
673 static bool can_front_overwrite(struct badblocks *bb, int prev, in can_front_overwrite() argument
676 u64 *p = bb->page; in can_front_overwrite()
679 WARN_ON(!overlap_front(bb, prev, bad)); in can_front_overwrite()
703 if ((bb->count + (*extra)) > MAX_BADBLOCKS) in can_front_overwrite()
716 static int front_overwrite(struct badblocks *bb, int prev, in front_overwrite() argument
719 u64 *p = bb->page; in front_overwrite()
733 (bb->count - prev - 1) * 8); in front_overwrite()
747 (bb->count - prev - 1) * 8); in front_overwrite()
761 (bb->count - prev - 1) * 8); in front_overwrite()
778 static int insert_at(struct badblocks *bb, int at, struct badblocks_context *bad) in insert_at() argument
780 u64 *p = bb->page; in insert_at()
783 WARN_ON(badblocks_full(bb)); in insert_at()
786 if (at < bb->count) in insert_at()
787 memmove(p + at + 1, p + at, (bb->count - at) * 8); in insert_at()
793 static void badblocks_update_acked(struct badblocks *bb) in badblocks_update_acked() argument
796 u64 *p = bb->page; in badblocks_update_acked()
799 if (!bb->unacked_exist) in badblocks_update_acked()
802 for (i = 0; i < bb->count ; i++) { in badblocks_update_acked()
810 bb->unacked_exist = 0; in badblocks_update_acked()
817 static bool try_adjacent_combine(struct badblocks *bb, int prev) in try_adjacent_combine() argument
819 u64 *p = bb->page; in try_adjacent_combine()
821 if (prev >= 0 && (prev + 1) < bb->count && in try_adjacent_combine()
829 if ((prev + 2) < bb->count) in try_adjacent_combine()
831 (bb->count - (prev + 2)) * 8); in try_adjacent_combine()
832 bb->count--; in try_adjacent_combine()
839 static bool _badblocks_set(struct badblocks *bb, sector_t s, sector_t sectors, in _badblocks_set() argument
848 if (bb->shift < 0) in _badblocks_set()
856 if (bb->shift) { in _badblocks_set()
860 rounddown(s, 1 << bb->shift); in _badblocks_set()
861 roundup(next, 1 << bb->shift); in _badblocks_set()
865 write_seqlock_irqsave(&bb->lock, flags); in _badblocks_set()
868 p = bb->page; in _badblocks_set()
875 if (badblocks_full(bb)) in _badblocks_set()
878 if (badblocks_empty(bb)) { in _badblocks_set()
879 len = insert_at(bb, 0, &bad); in _badblocks_set()
880 bb->count++; in _badblocks_set()
885 prev = prev_badblocks(bb, &bad, hint); in _badblocks_set()
892 len = insert_at(bb, 0, &bad); in _badblocks_set()
893 bb->count++; in _badblocks_set()
900 if (can_combine_front(bb, prev, &bad)) { in _badblocks_set()
901 front_combine(bb, prev); in _badblocks_set()
902 bb->count--; in _badblocks_set()
908 if (overlap_front(bb, prev, &bad)) { in _badblocks_set()
909 if (can_merge_front(bb, prev, &bad)) { in _badblocks_set()
910 len = front_merge(bb, prev, &bad); in _badblocks_set()
915 if (!can_front_overwrite(bb, prev, &bad, &extra)) { in _badblocks_set()
925 len = front_overwrite(bb, prev, &bad, extra); in _badblocks_set()
927 bb->count += extra; in _badblocks_set()
929 if (can_combine_front(bb, prev, &bad)) { in _badblocks_set()
930 front_combine(bb, prev); in _badblocks_set()
931 bb->count--; in _badblocks_set()
938 if (can_merge_front(bb, prev, &bad)) { in _badblocks_set()
939 len = front_merge(bb, prev, &bad); in _badblocks_set()
946 if ((prev + 1) < bb->count && in _badblocks_set()
947 overlap_behind(bb, &bad, prev + 1)) in _badblocks_set()
951 len = insert_at(bb, prev + 1, &bad); in _badblocks_set()
952 bb->count++; in _badblocks_set()
968 try_adjacent_combine(bb, prev); in _badblocks_set()
972 set_changed(bb); in _badblocks_set()
975 bb->unacked_exist = 1; in _badblocks_set()
977 badblocks_update_acked(bb); in _badblocks_set()
980 write_sequnlock_irqrestore(&bb->lock, flags); in _badblocks_set()
990 * the caller to reduce bb->count.
992 static int front_clear(struct badblocks *bb, int prev, in front_clear() argument
997 u64 *p = bb->page; in front_clear()
1010 if ((prev + 1) < bb->count) in front_clear()
1012 (bb->count - prev - 1) * 8); in front_clear()
1035 static int front_splitting_clear(struct badblocks *bb, int prev, in front_splitting_clear() argument
1038 u64 *p = bb->page; in front_splitting_clear()
1047 memmove(p + prev + 2, p + prev + 1, (bb->count - prev - 1) * 8); in front_splitting_clear()
1053 static bool _badblocks_clear(struct badblocks *bb, sector_t s, sector_t sectors) in _badblocks_clear() argument
1060 if (bb->shift < 0) in _badblocks_clear()
1068 if (bb->shift) { in _badblocks_clear()
1078 roundup(s, 1 << bb->shift); in _badblocks_clear()
1079 rounddown(target, 1 << bb->shift); in _badblocks_clear()
1083 write_seqlock_irq(&bb->lock); in _badblocks_clear()
1086 p = bb->page; in _badblocks_clear()
1092 if (badblocks_empty(bb)) { in _badblocks_clear()
1099 prev = prev_badblocks(bb, &bad, hint); in _badblocks_clear()
1103 if (overlap_behind(bb, &bad, 0)) { in _badblocks_clear()
1118 if ((prev + 1) >= bb->count && !overlap_front(bb, prev, &bad)) { in _badblocks_clear()
1125 if (badblocks_full(bb) && (BB_OFFSET(p[prev]) < bad.start) && in _badblocks_clear()
1131 if (overlap_front(bb, prev, &bad)) { in _badblocks_clear()
1135 if ((bb->count + 1) <= MAX_BADBLOCKS) { in _badblocks_clear()
1136 len = front_splitting_clear(bb, prev, &bad); in _badblocks_clear()
1137 bb->count += 1; in _badblocks_clear()
1146 len = front_clear(bb, prev, &bad, &deleted); in _badblocks_clear()
1147 bb->count -= deleted; in _badblocks_clear()
1156 if ((prev + 1) < bb->count && overlap_behind(bb, &bad, prev + 1)) { in _badblocks_clear()
1177 badblocks_update_acked(bb); in _badblocks_clear()
1178 set_changed(bb); in _badblocks_clear()
1181 write_sequnlock_irq(&bb->lock); in _badblocks_clear()
1190 static int _badblocks_check(struct badblocks *bb, sector_t s, sector_t sectors, in _badblocks_check() argument
1197 u64 *p = bb->page; in _badblocks_check()
1204 if (badblocks_empty(bb)) { in _badblocks_check()
1209 prev = prev_badblocks(bb, &bad, hint); in _badblocks_check()
1213 ((prev + 1) >= bb->count) && !overlap_front(bb, prev, &bad)) { in _badblocks_check()
1219 if ((prev >= 0) && overlap_front(bb, prev, &bad)) { in _badblocks_check()
1239 if ((prev + 1) < bb->count && overlap_behind(bb, &bad, prev + 1)) { in _badblocks_check()
1269 * @bb: the badblocks structure that holds all badblock information
1301 int badblocks_check(struct badblocks *bb, sector_t s, sector_t sectors, in badblocks_check() argument
1307 WARN_ON(bb->shift < 0 || sectors == 0); in badblocks_check()
1309 if (bb->shift > 0) { in badblocks_check()
1313 rounddown(s, 1 << bb->shift); in badblocks_check()
1314 roundup(target, 1 << bb->shift); in badblocks_check()
1319 seq = read_seqbegin(&bb->lock); in badblocks_check()
1320 rv = _badblocks_check(bb, s, sectors, first_bad, bad_sectors); in badblocks_check()
1321 if (read_seqretry(&bb->lock, seq)) in badblocks_check()
1330 * @bb: the badblocks structure that holds all badblock information
1344 bool badblocks_set(struct badblocks *bb, sector_t s, sector_t sectors, in badblocks_set() argument
1347 return _badblocks_set(bb, s, sectors, acknowledged); in badblocks_set()
1353 * @bb: the badblocks structure that holds all badblock information
1365 bool badblocks_clear(struct badblocks *bb, sector_t s, sector_t sectors) in badblocks_clear() argument
1367 return _badblocks_clear(bb, s, sectors); in badblocks_clear()
1373 * @bb: the badblocks structure that holds all badblock information
1378 void ack_all_badblocks(struct badblocks *bb) in ack_all_badblocks() argument
1380 if (bb->page == NULL || bb->changed) in ack_all_badblocks()
1383 write_seqlock_irq(&bb->lock); in ack_all_badblocks()
1385 if (bb->changed == 0 && bb->unacked_exist) { in ack_all_badblocks()
1386 u64 *p = bb->page; in ack_all_badblocks()
1389 for (i = 0; i < bb->count ; i++) { in ack_all_badblocks()
1398 for (i = 0; i < bb->count ; i++) in ack_all_badblocks()
1399 while (try_adjacent_combine(bb, i)) in ack_all_badblocks()
1402 bb->unacked_exist = 0; in ack_all_badblocks()
1404 write_sequnlock_irq(&bb->lock); in ack_all_badblocks()
1410 * @bb: the badblocks structure that holds all badblock information
1417 ssize_t badblocks_show(struct badblocks *bb, char *page, int unack) in badblocks_show() argument
1421 u64 *p = bb->page; in badblocks_show()
1424 if (bb->shift < 0) in badblocks_show()
1428 seq = read_seqbegin(&bb->lock); in badblocks_show()
1433 while (len < PAGE_SIZE && i < bb->count) { in badblocks_show()
1444 (unsigned long long)s << bb->shift, in badblocks_show()
1445 length << bb->shift); in badblocks_show()
1448 bb->unacked_exist = 0; in badblocks_show()
1450 if (read_seqretry(&bb->lock, seq)) in badblocks_show()
1459 * @bb: the badblocks structure that holds all badblock information
1467 ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len, in badblocks_store() argument
1487 if (!badblocks_set(bb, sector, length, !unack)) in badblocks_store()
1494 static int __badblocks_init(struct device *dev, struct badblocks *bb, in __badblocks_init() argument
1497 bb->dev = dev; in __badblocks_init()
1498 bb->count = 0; in __badblocks_init()
1500 bb->shift = 0; in __badblocks_init()
1502 bb->shift = -1; in __badblocks_init()
1504 bb->page = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL); in __badblocks_init()
1506 bb->page = kzalloc(PAGE_SIZE, GFP_KERNEL); in __badblocks_init()
1507 if (!bb->page) { in __badblocks_init()
1508 bb->shift = -1; in __badblocks_init()
1511 seqlock_init(&bb->lock); in __badblocks_init()
1518 * @bb: the badblocks structure that holds all badblock information
1525 int badblocks_init(struct badblocks *bb, int enable) in badblocks_init() argument
1527 return __badblocks_init(NULL, bb, enable); in badblocks_init()
1531 int devm_init_badblocks(struct device *dev, struct badblocks *bb) in devm_init_badblocks() argument
1533 if (!bb) in devm_init_badblocks()
1535 return __badblocks_init(dev, bb, 1); in devm_init_badblocks()
1541 * @bb: the badblocks structure that holds all badblock information
1543 void badblocks_exit(struct badblocks *bb) in badblocks_exit() argument
1545 if (!bb) in badblocks_exit()
1547 if (bb->dev) in badblocks_exit()
1548 devm_kfree(bb->dev, bb->page); in badblocks_exit()
1550 kfree(bb->page); in badblocks_exit()
1551 bb->page = NULL; in badblocks_exit()