18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/fs/hpfs/buffer.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  general buffer i/o
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#include <linux/sched.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
128c2ecf20Sopenharmony_ci#include "hpfs_fn.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_cisecno hpfs_search_hotfix_map(struct super_block *s, secno sec)
158c2ecf20Sopenharmony_ci{
168c2ecf20Sopenharmony_ci	unsigned i;
178c2ecf20Sopenharmony_ci	struct hpfs_sb_info *sbi = hpfs_sb(s);
188c2ecf20Sopenharmony_ci	for (i = 0; unlikely(i < sbi->n_hotfixes); i++) {
198c2ecf20Sopenharmony_ci		if (sbi->hotfix_from[i] == sec) {
208c2ecf20Sopenharmony_ci			return sbi->hotfix_to[i];
218c2ecf20Sopenharmony_ci		}
228c2ecf20Sopenharmony_ci	}
238c2ecf20Sopenharmony_ci	return sec;
248c2ecf20Sopenharmony_ci}
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ciunsigned hpfs_search_hotfix_map_for_range(struct super_block *s, secno sec, unsigned n)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	unsigned i;
298c2ecf20Sopenharmony_ci	struct hpfs_sb_info *sbi = hpfs_sb(s);
308c2ecf20Sopenharmony_ci	for (i = 0; unlikely(i < sbi->n_hotfixes); i++) {
318c2ecf20Sopenharmony_ci		if (sbi->hotfix_from[i] >= sec && sbi->hotfix_from[i] < sec + n) {
328c2ecf20Sopenharmony_ci			n = sbi->hotfix_from[i] - sec;
338c2ecf20Sopenharmony_ci		}
348c2ecf20Sopenharmony_ci	}
358c2ecf20Sopenharmony_ci	return n;
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_civoid hpfs_prefetch_sectors(struct super_block *s, unsigned secno, int n)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	struct buffer_head *bh;
418c2ecf20Sopenharmony_ci	struct blk_plug plug;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (n <= 0 || unlikely(secno >= hpfs_sb(s)->sb_fs_size))
448c2ecf20Sopenharmony_ci		return;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	if (unlikely(hpfs_search_hotfix_map_for_range(s, secno, n) != n))
478c2ecf20Sopenharmony_ci		return;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	bh = sb_find_get_block(s, secno);
508c2ecf20Sopenharmony_ci	if (bh) {
518c2ecf20Sopenharmony_ci		if (buffer_uptodate(bh)) {
528c2ecf20Sopenharmony_ci			brelse(bh);
538c2ecf20Sopenharmony_ci			return;
548c2ecf20Sopenharmony_ci		}
558c2ecf20Sopenharmony_ci		brelse(bh);
568c2ecf20Sopenharmony_ci	}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	blk_start_plug(&plug);
598c2ecf20Sopenharmony_ci	while (n > 0) {
608c2ecf20Sopenharmony_ci		if (unlikely(secno >= hpfs_sb(s)->sb_fs_size))
618c2ecf20Sopenharmony_ci			break;
628c2ecf20Sopenharmony_ci		sb_breadahead(s, secno);
638c2ecf20Sopenharmony_ci		secno++;
648c2ecf20Sopenharmony_ci		n--;
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci	blk_finish_plug(&plug);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci/* Map a sector into a buffer and return pointers to it and to the buffer. */
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_civoid *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head **bhp,
728c2ecf20Sopenharmony_ci		 int ahead)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	struct buffer_head *bh;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	hpfs_lock_assert(s);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	hpfs_prefetch_sectors(s, secno, ahead);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	cond_resched();
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	*bhp = bh = sb_bread(s, hpfs_search_hotfix_map(s, secno));
838c2ecf20Sopenharmony_ci	if (bh != NULL)
848c2ecf20Sopenharmony_ci		return bh->b_data;
858c2ecf20Sopenharmony_ci	else {
868c2ecf20Sopenharmony_ci		pr_err("%s(): read error\n", __func__);
878c2ecf20Sopenharmony_ci		return NULL;
888c2ecf20Sopenharmony_ci	}
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/* Like hpfs_map_sector but don't read anything */
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_civoid *hpfs_get_sector(struct super_block *s, unsigned secno, struct buffer_head **bhp)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	struct buffer_head *bh;
968c2ecf20Sopenharmony_ci	/*return hpfs_map_sector(s, secno, bhp, 0);*/
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	hpfs_lock_assert(s);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	cond_resched();
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	if ((*bhp = bh = sb_getblk(s, hpfs_search_hotfix_map(s, secno))) != NULL) {
1038c2ecf20Sopenharmony_ci		if (!buffer_uptodate(bh)) wait_on_buffer(bh);
1048c2ecf20Sopenharmony_ci		set_buffer_uptodate(bh);
1058c2ecf20Sopenharmony_ci		return bh->b_data;
1068c2ecf20Sopenharmony_ci	} else {
1078c2ecf20Sopenharmony_ci		pr_err("%s(): getblk failed\n", __func__);
1088c2ecf20Sopenharmony_ci		return NULL;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/* Map 4 sectors into a 4buffer and return pointers to it and to the buffer. */
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_civoid *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffer_head *qbh,
1158c2ecf20Sopenharmony_ci		   int ahead)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	char *data;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	hpfs_lock_assert(s);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	cond_resched();
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (secno & 3) {
1248c2ecf20Sopenharmony_ci		pr_err("%s(): unaligned read\n", __func__);
1258c2ecf20Sopenharmony_ci		return NULL;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	hpfs_prefetch_sectors(s, secno, 4 + ahead);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	if (!hpfs_map_sector(s, secno + 0, &qbh->bh[0], 0)) goto bail0;
1318c2ecf20Sopenharmony_ci	if (!hpfs_map_sector(s, secno + 1, &qbh->bh[1], 0)) goto bail1;
1328c2ecf20Sopenharmony_ci	if (!hpfs_map_sector(s, secno + 2, &qbh->bh[2], 0)) goto bail2;
1338c2ecf20Sopenharmony_ci	if (!hpfs_map_sector(s, secno + 3, &qbh->bh[3], 0)) goto bail3;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	if (likely(qbh->bh[1]->b_data == qbh->bh[0]->b_data + 1 * 512) &&
1368c2ecf20Sopenharmony_ci	    likely(qbh->bh[2]->b_data == qbh->bh[0]->b_data + 2 * 512) &&
1378c2ecf20Sopenharmony_ci	    likely(qbh->bh[3]->b_data == qbh->bh[0]->b_data + 3 * 512)) {
1388c2ecf20Sopenharmony_ci		return qbh->data = qbh->bh[0]->b_data;
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	qbh->data = data = kmalloc(2048, GFP_NOFS);
1428c2ecf20Sopenharmony_ci	if (!data) {
1438c2ecf20Sopenharmony_ci		pr_err("%s(): out of memory\n", __func__);
1448c2ecf20Sopenharmony_ci		goto bail4;
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	memcpy(data + 0 * 512, qbh->bh[0]->b_data, 512);
1488c2ecf20Sopenharmony_ci	memcpy(data + 1 * 512, qbh->bh[1]->b_data, 512);
1498c2ecf20Sopenharmony_ci	memcpy(data + 2 * 512, qbh->bh[2]->b_data, 512);
1508c2ecf20Sopenharmony_ci	memcpy(data + 3 * 512, qbh->bh[3]->b_data, 512);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	return data;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci bail4:
1558c2ecf20Sopenharmony_ci	brelse(qbh->bh[3]);
1568c2ecf20Sopenharmony_ci bail3:
1578c2ecf20Sopenharmony_ci	brelse(qbh->bh[2]);
1588c2ecf20Sopenharmony_ci bail2:
1598c2ecf20Sopenharmony_ci	brelse(qbh->bh[1]);
1608c2ecf20Sopenharmony_ci bail1:
1618c2ecf20Sopenharmony_ci	brelse(qbh->bh[0]);
1628c2ecf20Sopenharmony_ci bail0:
1638c2ecf20Sopenharmony_ci	return NULL;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci/* Don't read sectors */
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_civoid *hpfs_get_4sectors(struct super_block *s, unsigned secno,
1698c2ecf20Sopenharmony_ci                          struct quad_buffer_head *qbh)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	cond_resched();
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	hpfs_lock_assert(s);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (secno & 3) {
1768c2ecf20Sopenharmony_ci		pr_err("%s(): unaligned read\n", __func__);
1778c2ecf20Sopenharmony_ci		return NULL;
1788c2ecf20Sopenharmony_ci	}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	if (!hpfs_get_sector(s, secno + 0, &qbh->bh[0])) goto bail0;
1818c2ecf20Sopenharmony_ci	if (!hpfs_get_sector(s, secno + 1, &qbh->bh[1])) goto bail1;
1828c2ecf20Sopenharmony_ci	if (!hpfs_get_sector(s, secno + 2, &qbh->bh[2])) goto bail2;
1838c2ecf20Sopenharmony_ci	if (!hpfs_get_sector(s, secno + 3, &qbh->bh[3])) goto bail3;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (likely(qbh->bh[1]->b_data == qbh->bh[0]->b_data + 1 * 512) &&
1868c2ecf20Sopenharmony_ci	    likely(qbh->bh[2]->b_data == qbh->bh[0]->b_data + 2 * 512) &&
1878c2ecf20Sopenharmony_ci	    likely(qbh->bh[3]->b_data == qbh->bh[0]->b_data + 3 * 512)) {
1888c2ecf20Sopenharmony_ci		return qbh->data = qbh->bh[0]->b_data;
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	if (!(qbh->data = kmalloc(2048, GFP_NOFS))) {
1928c2ecf20Sopenharmony_ci		pr_err("%s(): out of memory\n", __func__);
1938c2ecf20Sopenharmony_ci		goto bail4;
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci	return qbh->data;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cibail4:
1988c2ecf20Sopenharmony_ci	brelse(qbh->bh[3]);
1998c2ecf20Sopenharmony_cibail3:
2008c2ecf20Sopenharmony_ci	brelse(qbh->bh[2]);
2018c2ecf20Sopenharmony_cibail2:
2028c2ecf20Sopenharmony_ci	brelse(qbh->bh[1]);
2038c2ecf20Sopenharmony_cibail1:
2048c2ecf20Sopenharmony_ci	brelse(qbh->bh[0]);
2058c2ecf20Sopenharmony_cibail0:
2068c2ecf20Sopenharmony_ci	return NULL;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_civoid hpfs_brelse4(struct quad_buffer_head *qbh)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	if (unlikely(qbh->data != qbh->bh[0]->b_data))
2138c2ecf20Sopenharmony_ci		kfree(qbh->data);
2148c2ecf20Sopenharmony_ci	brelse(qbh->bh[0]);
2158c2ecf20Sopenharmony_ci	brelse(qbh->bh[1]);
2168c2ecf20Sopenharmony_ci	brelse(qbh->bh[2]);
2178c2ecf20Sopenharmony_ci	brelse(qbh->bh[3]);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_civoid hpfs_mark_4buffers_dirty(struct quad_buffer_head *qbh)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	if (unlikely(qbh->data != qbh->bh[0]->b_data)) {
2238c2ecf20Sopenharmony_ci		memcpy(qbh->bh[0]->b_data, qbh->data + 0 * 512, 512);
2248c2ecf20Sopenharmony_ci		memcpy(qbh->bh[1]->b_data, qbh->data + 1 * 512, 512);
2258c2ecf20Sopenharmony_ci		memcpy(qbh->bh[2]->b_data, qbh->data + 2 * 512, 512);
2268c2ecf20Sopenharmony_ci		memcpy(qbh->bh[3]->b_data, qbh->data + 3 * 512, 512);
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci	mark_buffer_dirty(qbh->bh[0]);
2298c2ecf20Sopenharmony_ci	mark_buffer_dirty(qbh->bh[1]);
2308c2ecf20Sopenharmony_ci	mark_buffer_dirty(qbh->bh[2]);
2318c2ecf20Sopenharmony_ci	mark_buffer_dirty(qbh->bh[3]);
2328c2ecf20Sopenharmony_ci}
233