xref: /openbmc/linux/fs/hpfs/buffer.c (revision 9fa88c5d)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  linux/fs/hpfs/buffer.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  *  general buffer i/o
81da177e4SLinus Torvalds  */
9e8edc6e0SAlexey Dobriyan #include <linux/sched.h>
105a0e3ad6STejun Heo #include <linux/slab.h>
11275f495dSMikulas Patocka #include <linux/blkdev.h>
121da177e4SLinus Torvalds #include "hpfs_fn.h"
131da177e4SLinus Torvalds 
hpfs_search_hotfix_map(struct super_block * s,secno sec)14a64eefaaSMikulas Patocka secno hpfs_search_hotfix_map(struct super_block *s, secno sec)
15a64eefaaSMikulas Patocka {
16a64eefaaSMikulas Patocka 	unsigned i;
17a64eefaaSMikulas Patocka 	struct hpfs_sb_info *sbi = hpfs_sb(s);
18a64eefaaSMikulas Patocka 	for (i = 0; unlikely(i < sbi->n_hotfixes); i++) {
19a64eefaaSMikulas Patocka 		if (sbi->hotfix_from[i] == sec) {
20a64eefaaSMikulas Patocka 			return sbi->hotfix_to[i];
21a64eefaaSMikulas Patocka 		}
22a64eefaaSMikulas Patocka 	}
23a64eefaaSMikulas Patocka 	return sec;
24a64eefaaSMikulas Patocka }
25a64eefaaSMikulas Patocka 
hpfs_search_hotfix_map_for_range(struct super_block * s,secno sec,unsigned n)26a64eefaaSMikulas Patocka unsigned hpfs_search_hotfix_map_for_range(struct super_block *s, secno sec, unsigned n)
27a64eefaaSMikulas Patocka {
28a64eefaaSMikulas Patocka 	unsigned i;
29a64eefaaSMikulas Patocka 	struct hpfs_sb_info *sbi = hpfs_sb(s);
30a64eefaaSMikulas Patocka 	for (i = 0; unlikely(i < sbi->n_hotfixes); i++) {
31a64eefaaSMikulas Patocka 		if (sbi->hotfix_from[i] >= sec && sbi->hotfix_from[i] < sec + n) {
32a64eefaaSMikulas Patocka 			n = sbi->hotfix_from[i] - sec;
33a64eefaaSMikulas Patocka 		}
34a64eefaaSMikulas Patocka 	}
35a64eefaaSMikulas Patocka 	return n;
36a64eefaaSMikulas Patocka }
37a64eefaaSMikulas Patocka 
hpfs_prefetch_sectors(struct super_block * s,unsigned secno,int n)38275f495dSMikulas Patocka void hpfs_prefetch_sectors(struct super_block *s, unsigned secno, int n)
39275f495dSMikulas Patocka {
40275f495dSMikulas Patocka 	struct buffer_head *bh;
41275f495dSMikulas Patocka 	struct blk_plug plug;
42275f495dSMikulas Patocka 
43275f495dSMikulas Patocka 	if (n <= 0 || unlikely(secno >= hpfs_sb(s)->sb_fs_size))
44275f495dSMikulas Patocka 		return;
45275f495dSMikulas Patocka 
46a64eefaaSMikulas Patocka 	if (unlikely(hpfs_search_hotfix_map_for_range(s, secno, n) != n))
47a64eefaaSMikulas Patocka 		return;
48a64eefaaSMikulas Patocka 
49275f495dSMikulas Patocka 	bh = sb_find_get_block(s, secno);
50275f495dSMikulas Patocka 	if (bh) {
51275f495dSMikulas Patocka 		if (buffer_uptodate(bh)) {
52275f495dSMikulas Patocka 			brelse(bh);
53275f495dSMikulas Patocka 			return;
54275f495dSMikulas Patocka 		}
55275f495dSMikulas Patocka 		brelse(bh);
569fa88c5dSZou Wei 	}
57275f495dSMikulas Patocka 
58275f495dSMikulas Patocka 	blk_start_plug(&plug);
59275f495dSMikulas Patocka 	while (n > 0) {
60275f495dSMikulas Patocka 		if (unlikely(secno >= hpfs_sb(s)->sb_fs_size))
61275f495dSMikulas Patocka 			break;
62275f495dSMikulas Patocka 		sb_breadahead(s, secno);
63275f495dSMikulas Patocka 		secno++;
64275f495dSMikulas Patocka 		n--;
65275f495dSMikulas Patocka 	}
66275f495dSMikulas Patocka 	blk_finish_plug(&plug);
67275f495dSMikulas Patocka }
68275f495dSMikulas Patocka 
691da177e4SLinus Torvalds /* Map a sector into a buffer and return pointers to it and to the buffer. */
701da177e4SLinus Torvalds 
hpfs_map_sector(struct super_block * s,unsigned secno,struct buffer_head ** bhp,int ahead)711da177e4SLinus Torvalds void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head **bhp,
721da177e4SLinus Torvalds 		 int ahead)
731da177e4SLinus Torvalds {
741da177e4SLinus Torvalds 	struct buffer_head *bh;
751da177e4SLinus Torvalds 
767dd29d8dSMikulas Patocka 	hpfs_lock_assert(s);
777dd29d8dSMikulas Patocka 
78275f495dSMikulas Patocka 	hpfs_prefetch_sectors(s, secno, ahead);
79275f495dSMikulas Patocka 
801da177e4SLinus Torvalds 	cond_resched();
811da177e4SLinus Torvalds 
82a64eefaaSMikulas Patocka 	*bhp = bh = sb_bread(s, hpfs_search_hotfix_map(s, secno));
831da177e4SLinus Torvalds 	if (bh != NULL)
841da177e4SLinus Torvalds 		return bh->b_data;
851da177e4SLinus Torvalds 	else {
86a19189e5SFabian Frederick 		pr_err("%s(): read error\n", __func__);
871da177e4SLinus Torvalds 		return NULL;
881da177e4SLinus Torvalds 	}
891da177e4SLinus Torvalds }
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds /* Like hpfs_map_sector but don't read anything */
921da177e4SLinus Torvalds 
hpfs_get_sector(struct super_block * s,unsigned secno,struct buffer_head ** bhp)931da177e4SLinus Torvalds void *hpfs_get_sector(struct super_block *s, unsigned secno, struct buffer_head **bhp)
941da177e4SLinus Torvalds {
951da177e4SLinus Torvalds 	struct buffer_head *bh;
961da177e4SLinus Torvalds 	/*return hpfs_map_sector(s, secno, bhp, 0);*/
971da177e4SLinus Torvalds 
987dd29d8dSMikulas Patocka 	hpfs_lock_assert(s);
997dd29d8dSMikulas Patocka 
1001da177e4SLinus Torvalds 	cond_resched();
1011da177e4SLinus Torvalds 
102a64eefaaSMikulas Patocka 	if ((*bhp = bh = sb_getblk(s, hpfs_search_hotfix_map(s, secno))) != NULL) {
1031da177e4SLinus Torvalds 		if (!buffer_uptodate(bh)) wait_on_buffer(bh);
1041da177e4SLinus Torvalds 		set_buffer_uptodate(bh);
1051da177e4SLinus Torvalds 		return bh->b_data;
1061da177e4SLinus Torvalds 	} else {
107a19189e5SFabian Frederick 		pr_err("%s(): getblk failed\n", __func__);
1081da177e4SLinus Torvalds 		return NULL;
1091da177e4SLinus Torvalds 	}
1101da177e4SLinus Torvalds }
1111da177e4SLinus Torvalds 
1121da177e4SLinus Torvalds /* Map 4 sectors into a 4buffer and return pointers to it and to the buffer. */
1131da177e4SLinus Torvalds 
hpfs_map_4sectors(struct super_block * s,unsigned secno,struct quad_buffer_head * qbh,int ahead)1141da177e4SLinus Torvalds void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffer_head *qbh,
1151da177e4SLinus Torvalds 		   int ahead)
1161da177e4SLinus Torvalds {
1171da177e4SLinus Torvalds 	char *data;
1181da177e4SLinus Torvalds 
1197dd29d8dSMikulas Patocka 	hpfs_lock_assert(s);
1207dd29d8dSMikulas Patocka 
1211da177e4SLinus Torvalds 	cond_resched();
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds 	if (secno & 3) {
124a19189e5SFabian Frederick 		pr_err("%s(): unaligned read\n", __func__);
1251da177e4SLinus Torvalds 		return NULL;
1261da177e4SLinus Torvalds 	}
1271da177e4SLinus Torvalds 
128275f495dSMikulas Patocka 	hpfs_prefetch_sectors(s, secno, 4 + ahead);
129275f495dSMikulas Patocka 
130a64eefaaSMikulas Patocka 	if (!hpfs_map_sector(s, secno + 0, &qbh->bh[0], 0)) goto bail0;
131a64eefaaSMikulas Patocka 	if (!hpfs_map_sector(s, secno + 1, &qbh->bh[1], 0)) goto bail1;
132a64eefaaSMikulas Patocka 	if (!hpfs_map_sector(s, secno + 2, &qbh->bh[2], 0)) goto bail2;
133a64eefaaSMikulas Patocka 	if (!hpfs_map_sector(s, secno + 3, &qbh->bh[3], 0)) goto bail3;
1341c0b8a7aSMikulas Patocka 
1351c0b8a7aSMikulas Patocka 	if (likely(qbh->bh[1]->b_data == qbh->bh[0]->b_data + 1 * 512) &&
1361c0b8a7aSMikulas Patocka 	    likely(qbh->bh[2]->b_data == qbh->bh[0]->b_data + 2 * 512) &&
1371c0b8a7aSMikulas Patocka 	    likely(qbh->bh[3]->b_data == qbh->bh[0]->b_data + 3 * 512)) {
1381c0b8a7aSMikulas Patocka 		return qbh->data = qbh->bh[0]->b_data;
1391c0b8a7aSMikulas Patocka 	}
1401c0b8a7aSMikulas Patocka 
141f52720caSPanagiotis Issaris 	qbh->data = data = kmalloc(2048, GFP_NOFS);
1421da177e4SLinus Torvalds 	if (!data) {
143a19189e5SFabian Frederick 		pr_err("%s(): out of memory\n", __func__);
1441c0b8a7aSMikulas Patocka 		goto bail4;
1451da177e4SLinus Torvalds 	}
1461da177e4SLinus Torvalds 
1471c0b8a7aSMikulas Patocka 	memcpy(data + 0 * 512, qbh->bh[0]->b_data, 512);
1481c0b8a7aSMikulas Patocka 	memcpy(data + 1 * 512, qbh->bh[1]->b_data, 512);
1491c0b8a7aSMikulas Patocka 	memcpy(data + 2 * 512, qbh->bh[2]->b_data, 512);
1501c0b8a7aSMikulas Patocka 	memcpy(data + 3 * 512, qbh->bh[3]->b_data, 512);
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds 	return data;
1531da177e4SLinus Torvalds 
1541c0b8a7aSMikulas Patocka  bail4:
1551c0b8a7aSMikulas Patocka 	brelse(qbh->bh[3]);
1561da177e4SLinus Torvalds  bail3:
1571da177e4SLinus Torvalds 	brelse(qbh->bh[2]);
1581da177e4SLinus Torvalds  bail2:
1591da177e4SLinus Torvalds 	brelse(qbh->bh[1]);
1601da177e4SLinus Torvalds  bail1:
1611da177e4SLinus Torvalds 	brelse(qbh->bh[0]);
1621da177e4SLinus Torvalds  bail0:
1631da177e4SLinus Torvalds 	return NULL;
1641da177e4SLinus Torvalds }
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds /* Don't read sectors */
1671da177e4SLinus Torvalds 
hpfs_get_4sectors(struct super_block * s,unsigned secno,struct quad_buffer_head * qbh)1681da177e4SLinus Torvalds void *hpfs_get_4sectors(struct super_block *s, unsigned secno,
1691da177e4SLinus Torvalds                           struct quad_buffer_head *qbh)
1701da177e4SLinus Torvalds {
1711da177e4SLinus Torvalds 	cond_resched();
1721da177e4SLinus Torvalds 
1737dd29d8dSMikulas Patocka 	hpfs_lock_assert(s);
1747dd29d8dSMikulas Patocka 
1751da177e4SLinus Torvalds 	if (secno & 3) {
176a19189e5SFabian Frederick 		pr_err("%s(): unaligned read\n", __func__);
1771da177e4SLinus Torvalds 		return NULL;
1781da177e4SLinus Torvalds 	}
1791da177e4SLinus Torvalds 
1801c0b8a7aSMikulas Patocka 	if (!hpfs_get_sector(s, secno + 0, &qbh->bh[0])) goto bail0;
1811c0b8a7aSMikulas Patocka 	if (!hpfs_get_sector(s, secno + 1, &qbh->bh[1])) goto bail1;
1821c0b8a7aSMikulas Patocka 	if (!hpfs_get_sector(s, secno + 2, &qbh->bh[2])) goto bail2;
1831c0b8a7aSMikulas Patocka 	if (!hpfs_get_sector(s, secno + 3, &qbh->bh[3])) goto bail3;
1841c0b8a7aSMikulas Patocka 
1851c0b8a7aSMikulas Patocka 	if (likely(qbh->bh[1]->b_data == qbh->bh[0]->b_data + 1 * 512) &&
1861c0b8a7aSMikulas Patocka 	    likely(qbh->bh[2]->b_data == qbh->bh[0]->b_data + 2 * 512) &&
1871c0b8a7aSMikulas Patocka 	    likely(qbh->bh[3]->b_data == qbh->bh[0]->b_data + 3 * 512)) {
1881c0b8a7aSMikulas Patocka 		return qbh->data = qbh->bh[0]->b_data;
1891c0b8a7aSMikulas Patocka 	}
1901c0b8a7aSMikulas Patocka 
1911da177e4SLinus Torvalds 	if (!(qbh->data = kmalloc(2048, GFP_NOFS))) {
192a19189e5SFabian Frederick 		pr_err("%s(): out of memory\n", __func__);
1931c0b8a7aSMikulas Patocka 		goto bail4;
1941da177e4SLinus Torvalds 	}
1951da177e4SLinus Torvalds 	return qbh->data;
1961da177e4SLinus Torvalds 
1971c0b8a7aSMikulas Patocka bail4:
1981c0b8a7aSMikulas Patocka 	brelse(qbh->bh[3]);
1991c0b8a7aSMikulas Patocka bail3:
2001c0b8a7aSMikulas Patocka 	brelse(qbh->bh[2]);
2011c0b8a7aSMikulas Patocka bail2:
2021c0b8a7aSMikulas Patocka 	brelse(qbh->bh[1]);
2031c0b8a7aSMikulas Patocka bail1:
2041c0b8a7aSMikulas Patocka 	brelse(qbh->bh[0]);
2051da177e4SLinus Torvalds bail0:
2061da177e4SLinus Torvalds 	return NULL;
2071da177e4SLinus Torvalds }
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 
hpfs_brelse4(struct quad_buffer_head * qbh)2101da177e4SLinus Torvalds void hpfs_brelse4(struct quad_buffer_head *qbh)
2111da177e4SLinus Torvalds {
2121c0b8a7aSMikulas Patocka 	if (unlikely(qbh->data != qbh->bh[0]->b_data))
2131da177e4SLinus Torvalds 		kfree(qbh->data);
2141c0b8a7aSMikulas Patocka 	brelse(qbh->bh[0]);
2151c0b8a7aSMikulas Patocka 	brelse(qbh->bh[1]);
2161c0b8a7aSMikulas Patocka 	brelse(qbh->bh[2]);
2171c0b8a7aSMikulas Patocka 	brelse(qbh->bh[3]);
2181da177e4SLinus Torvalds }
2191da177e4SLinus Torvalds 
hpfs_mark_4buffers_dirty(struct quad_buffer_head * qbh)2201da177e4SLinus Torvalds void hpfs_mark_4buffers_dirty(struct quad_buffer_head *qbh)
2211da177e4SLinus Torvalds {
2221c0b8a7aSMikulas Patocka 	if (unlikely(qbh->data != qbh->bh[0]->b_data)) {
2231c0b8a7aSMikulas Patocka 		memcpy(qbh->bh[0]->b_data, qbh->data + 0 * 512, 512);
2241c0b8a7aSMikulas Patocka 		memcpy(qbh->bh[1]->b_data, qbh->data + 1 * 512, 512);
2251da177e4SLinus Torvalds 		memcpy(qbh->bh[2]->b_data, qbh->data + 2 * 512, 512);
2261da177e4SLinus Torvalds 		memcpy(qbh->bh[3]->b_data, qbh->data + 3 * 512, 512);
2271c0b8a7aSMikulas Patocka 	}
2281da177e4SLinus Torvalds 	mark_buffer_dirty(qbh->bh[0]);
2291da177e4SLinus Torvalds 	mark_buffer_dirty(qbh->bh[1]);
2301da177e4SLinus Torvalds 	mark_buffer_dirty(qbh->bh[2]);
2311da177e4SLinus Torvalds 	mark_buffer_dirty(qbh->bh[3]);
2321da177e4SLinus Torvalds }
233