xref: /aosp_15_r20/external/erofs-utils/lib/cache.c (revision 33b1fccf6a0fada2c2875d400ed01119b7676ee5)
1*33b1fccfSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
2*33b1fccfSAndroid Build Coastguard Worker /*
3*33b1fccfSAndroid Build Coastguard Worker  * Copyright (C) 2018-2019 HUAWEI, Inc.
4*33b1fccfSAndroid Build Coastguard Worker  *             http://www.huawei.com/
5*33b1fccfSAndroid Build Coastguard Worker  * Created by Miao Xie <[email protected]>
6*33b1fccfSAndroid Build Coastguard Worker  * with heavy changes by Gao Xiang <[email protected]>
7*33b1fccfSAndroid Build Coastguard Worker  */
8*33b1fccfSAndroid Build Coastguard Worker #include <stdlib.h>
9*33b1fccfSAndroid Build Coastguard Worker #include <erofs/cache.h>
10*33b1fccfSAndroid Build Coastguard Worker #include "erofs/print.h"
11*33b1fccfSAndroid Build Coastguard Worker 
erofs_bh_flush_drop_directly(struct erofs_buffer_head * bh)12*33b1fccfSAndroid Build Coastguard Worker static int erofs_bh_flush_drop_directly(struct erofs_buffer_head *bh)
13*33b1fccfSAndroid Build Coastguard Worker {
14*33b1fccfSAndroid Build Coastguard Worker 	return erofs_bh_flush_generic_end(bh);
15*33b1fccfSAndroid Build Coastguard Worker }
16*33b1fccfSAndroid Build Coastguard Worker 
17*33b1fccfSAndroid Build Coastguard Worker const struct erofs_bhops erofs_drop_directly_bhops = {
18*33b1fccfSAndroid Build Coastguard Worker 	.flush = erofs_bh_flush_drop_directly,
19*33b1fccfSAndroid Build Coastguard Worker };
20*33b1fccfSAndroid Build Coastguard Worker 
erofs_bh_flush_skip_write(struct erofs_buffer_head * bh)21*33b1fccfSAndroid Build Coastguard Worker static int erofs_bh_flush_skip_write(struct erofs_buffer_head *bh)
22*33b1fccfSAndroid Build Coastguard Worker {
23*33b1fccfSAndroid Build Coastguard Worker 	return -EBUSY;
24*33b1fccfSAndroid Build Coastguard Worker }
25*33b1fccfSAndroid Build Coastguard Worker 
26*33b1fccfSAndroid Build Coastguard Worker const struct erofs_bhops erofs_skip_write_bhops = {
27*33b1fccfSAndroid Build Coastguard Worker 	.flush = erofs_bh_flush_skip_write,
28*33b1fccfSAndroid Build Coastguard Worker };
29*33b1fccfSAndroid Build Coastguard Worker 
erofs_buffer_init(struct erofs_sb_info * sbi,erofs_blk_t startblk)30*33b1fccfSAndroid Build Coastguard Worker struct erofs_bufmgr *erofs_buffer_init(struct erofs_sb_info *sbi,
31*33b1fccfSAndroid Build Coastguard Worker 				       erofs_blk_t startblk)
32*33b1fccfSAndroid Build Coastguard Worker {
33*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_bufmgr *bufmgr;
34*33b1fccfSAndroid Build Coastguard Worker 	int i, j;
35*33b1fccfSAndroid Build Coastguard Worker 
36*33b1fccfSAndroid Build Coastguard Worker 	bufmgr = malloc(sizeof(struct erofs_bufmgr));
37*33b1fccfSAndroid Build Coastguard Worker 	if (!bufmgr)
38*33b1fccfSAndroid Build Coastguard Worker 		return NULL;
39*33b1fccfSAndroid Build Coastguard Worker 
40*33b1fccfSAndroid Build Coastguard Worker 	init_list_head(&bufmgr->blkh.list);
41*33b1fccfSAndroid Build Coastguard Worker 	bufmgr->blkh.blkaddr = NULL_ADDR;
42*33b1fccfSAndroid Build Coastguard Worker 	bufmgr->last_mapped_block = &bufmgr->blkh;
43*33b1fccfSAndroid Build Coastguard Worker 
44*33b1fccfSAndroid Build Coastguard Worker 	for (i = 0; i < ARRAY_SIZE(bufmgr->mapped_buckets); i++)
45*33b1fccfSAndroid Build Coastguard Worker 		for (j = 0; j < ARRAY_SIZE(bufmgr->mapped_buckets[0]); j++)
46*33b1fccfSAndroid Build Coastguard Worker 			init_list_head(&bufmgr->mapped_buckets[i][j]);
47*33b1fccfSAndroid Build Coastguard Worker 	bufmgr->tail_blkaddr = startblk;
48*33b1fccfSAndroid Build Coastguard Worker 	bufmgr->sbi = sbi;
49*33b1fccfSAndroid Build Coastguard Worker 	return bufmgr;
50*33b1fccfSAndroid Build Coastguard Worker }
51*33b1fccfSAndroid Build Coastguard Worker 
erofs_bupdate_mapped(struct erofs_buffer_block * bb)52*33b1fccfSAndroid Build Coastguard Worker static void erofs_bupdate_mapped(struct erofs_buffer_block *bb)
53*33b1fccfSAndroid Build Coastguard Worker {
54*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_bufmgr *bmgr = bb->buffers.fsprivate;
55*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = bmgr->sbi;
56*33b1fccfSAndroid Build Coastguard Worker 	struct list_head *bkt;
57*33b1fccfSAndroid Build Coastguard Worker 
58*33b1fccfSAndroid Build Coastguard Worker 	if (bb->blkaddr == NULL_ADDR)
59*33b1fccfSAndroid Build Coastguard Worker 		return;
60*33b1fccfSAndroid Build Coastguard Worker 
61*33b1fccfSAndroid Build Coastguard Worker 	bkt = bmgr->mapped_buckets[bb->type] +
62*33b1fccfSAndroid Build Coastguard Worker 		(bb->buffers.off & (erofs_blksiz(sbi) - 1));
63*33b1fccfSAndroid Build Coastguard Worker 	list_del(&bb->mapped_list);
64*33b1fccfSAndroid Build Coastguard Worker 	list_add_tail(&bb->mapped_list, bkt);
65*33b1fccfSAndroid Build Coastguard Worker }
66*33b1fccfSAndroid Build Coastguard Worker 
67*33b1fccfSAndroid Build Coastguard Worker /* return occupied bytes in specific buffer block if succeed */
__erofs_battach(struct erofs_buffer_block * bb,struct erofs_buffer_head * bh,erofs_off_t incr,unsigned int alignsize,unsigned int extrasize,bool dryrun)68*33b1fccfSAndroid Build Coastguard Worker static int __erofs_battach(struct erofs_buffer_block *bb,
69*33b1fccfSAndroid Build Coastguard Worker 			   struct erofs_buffer_head *bh,
70*33b1fccfSAndroid Build Coastguard Worker 			   erofs_off_t incr,
71*33b1fccfSAndroid Build Coastguard Worker 			   unsigned int alignsize,
72*33b1fccfSAndroid Build Coastguard Worker 			   unsigned int extrasize,
73*33b1fccfSAndroid Build Coastguard Worker 			   bool dryrun)
74*33b1fccfSAndroid Build Coastguard Worker {
75*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_bufmgr *bmgr = bb->buffers.fsprivate;
76*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = bmgr->sbi;
77*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int blksiz = erofs_blksiz(sbi);
78*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int blkmask = blksiz - 1;
79*33b1fccfSAndroid Build Coastguard Worker 	erofs_off_t boff = bb->buffers.off;
80*33b1fccfSAndroid Build Coastguard Worker 	const erofs_off_t alignedoffset = roundup(boff, alignsize);
81*33b1fccfSAndroid Build Coastguard Worker 	const int oob = cmpsgn(roundup(((boff - 1) & blkmask) + 1, alignsize) +
82*33b1fccfSAndroid Build Coastguard Worker 					incr + extrasize, blksiz);
83*33b1fccfSAndroid Build Coastguard Worker 	bool tailupdate = false;
84*33b1fccfSAndroid Build Coastguard Worker 	erofs_blk_t blkaddr;
85*33b1fccfSAndroid Build Coastguard Worker 
86*33b1fccfSAndroid Build Coastguard Worker 	if (oob >= 0) {
87*33b1fccfSAndroid Build Coastguard Worker 		/* the next buffer block should be NULL_ADDR all the time */
88*33b1fccfSAndroid Build Coastguard Worker 		if (oob && list_next_entry(bb, list)->blkaddr != NULL_ADDR)
89*33b1fccfSAndroid Build Coastguard Worker 			return -EINVAL;
90*33b1fccfSAndroid Build Coastguard Worker 
91*33b1fccfSAndroid Build Coastguard Worker 		blkaddr = bb->blkaddr;
92*33b1fccfSAndroid Build Coastguard Worker 		if (blkaddr != NULL_ADDR) {
93*33b1fccfSAndroid Build Coastguard Worker 			tailupdate = (bmgr->tail_blkaddr == blkaddr +
94*33b1fccfSAndroid Build Coastguard Worker 				      BLK_ROUND_UP(sbi, boff));
95*33b1fccfSAndroid Build Coastguard Worker 			if (oob && !tailupdate)
96*33b1fccfSAndroid Build Coastguard Worker 				return -EINVAL;
97*33b1fccfSAndroid Build Coastguard Worker 		}
98*33b1fccfSAndroid Build Coastguard Worker 	}
99*33b1fccfSAndroid Build Coastguard Worker 
100*33b1fccfSAndroid Build Coastguard Worker 	if (!dryrun) {
101*33b1fccfSAndroid Build Coastguard Worker 		if (bh) {
102*33b1fccfSAndroid Build Coastguard Worker 			bh->off = alignedoffset;
103*33b1fccfSAndroid Build Coastguard Worker 			bh->block = bb;
104*33b1fccfSAndroid Build Coastguard Worker 			list_add_tail(&bh->list, &bb->buffers.list);
105*33b1fccfSAndroid Build Coastguard Worker 		}
106*33b1fccfSAndroid Build Coastguard Worker 		boff = alignedoffset + incr;
107*33b1fccfSAndroid Build Coastguard Worker 		bb->buffers.off = boff;
108*33b1fccfSAndroid Build Coastguard Worker 		/* need to update the tail_blkaddr */
109*33b1fccfSAndroid Build Coastguard Worker 		if (tailupdate)
110*33b1fccfSAndroid Build Coastguard Worker 			bmgr->tail_blkaddr = blkaddr +
111*33b1fccfSAndroid Build Coastguard Worker 						BLK_ROUND_UP(sbi, boff);
112*33b1fccfSAndroid Build Coastguard Worker 		erofs_bupdate_mapped(bb);
113*33b1fccfSAndroid Build Coastguard Worker 	}
114*33b1fccfSAndroid Build Coastguard Worker 	return ((alignedoffset + incr - 1) & blkmask) + 1;
115*33b1fccfSAndroid Build Coastguard Worker }
116*33b1fccfSAndroid Build Coastguard Worker 
erofs_bh_balloon(struct erofs_buffer_head * bh,erofs_off_t incr)117*33b1fccfSAndroid Build Coastguard Worker int erofs_bh_balloon(struct erofs_buffer_head *bh, erofs_off_t incr)
118*33b1fccfSAndroid Build Coastguard Worker {
119*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_buffer_block *const bb = bh->block;
120*33b1fccfSAndroid Build Coastguard Worker 
121*33b1fccfSAndroid Build Coastguard Worker 	/* should be the tail bh in the corresponding buffer block */
122*33b1fccfSAndroid Build Coastguard Worker 	if (bh->list.next != &bb->buffers.list)
123*33b1fccfSAndroid Build Coastguard Worker 		return -EINVAL;
124*33b1fccfSAndroid Build Coastguard Worker 
125*33b1fccfSAndroid Build Coastguard Worker 	return __erofs_battach(bb, NULL, incr, 1, 0, false);
126*33b1fccfSAndroid Build Coastguard Worker }
127*33b1fccfSAndroid Build Coastguard Worker 
erofs_bfind_for_attach(struct erofs_bufmgr * bmgr,int type,erofs_off_t size,unsigned int required_ext,unsigned int inline_ext,unsigned int alignsize,struct erofs_buffer_block ** bbp)128*33b1fccfSAndroid Build Coastguard Worker static int erofs_bfind_for_attach(struct erofs_bufmgr *bmgr,
129*33b1fccfSAndroid Build Coastguard Worker 				  int type, erofs_off_t size,
130*33b1fccfSAndroid Build Coastguard Worker 				  unsigned int required_ext,
131*33b1fccfSAndroid Build Coastguard Worker 				  unsigned int inline_ext,
132*33b1fccfSAndroid Build Coastguard Worker 				  unsigned int alignsize,
133*33b1fccfSAndroid Build Coastguard Worker 				  struct erofs_buffer_block **bbp)
134*33b1fccfSAndroid Build Coastguard Worker {
135*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int blksiz = erofs_blksiz(bmgr->sbi);
136*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_buffer_block *cur, *bb;
137*33b1fccfSAndroid Build Coastguard Worker 	unsigned int used0, used_before, usedmax, used;
138*33b1fccfSAndroid Build Coastguard Worker 	int ret;
139*33b1fccfSAndroid Build Coastguard Worker 
140*33b1fccfSAndroid Build Coastguard Worker 	used0 = ((size + required_ext) & (blksiz - 1)) + inline_ext;
141*33b1fccfSAndroid Build Coastguard Worker 	/* inline data should be in the same fs block */
142*33b1fccfSAndroid Build Coastguard Worker 	if (used0 > blksiz)
143*33b1fccfSAndroid Build Coastguard Worker 		return -ENOSPC;
144*33b1fccfSAndroid Build Coastguard Worker 
145*33b1fccfSAndroid Build Coastguard Worker 	if (!used0 || alignsize == blksiz) {
146*33b1fccfSAndroid Build Coastguard Worker 		*bbp = NULL;
147*33b1fccfSAndroid Build Coastguard Worker 		return 0;
148*33b1fccfSAndroid Build Coastguard Worker 	}
149*33b1fccfSAndroid Build Coastguard Worker 
150*33b1fccfSAndroid Build Coastguard Worker 	usedmax = 0;
151*33b1fccfSAndroid Build Coastguard Worker 	bb = NULL;
152*33b1fccfSAndroid Build Coastguard Worker 
153*33b1fccfSAndroid Build Coastguard Worker 	/* try to find a most-fit mapped buffer block first */
154*33b1fccfSAndroid Build Coastguard Worker 	if (size + required_ext + inline_ext >= blksiz)
155*33b1fccfSAndroid Build Coastguard Worker 		goto skip_mapped;
156*33b1fccfSAndroid Build Coastguard Worker 
157*33b1fccfSAndroid Build Coastguard Worker 	used_before = rounddown(blksiz -
158*33b1fccfSAndroid Build Coastguard Worker 				(size + required_ext + inline_ext), alignsize);
159*33b1fccfSAndroid Build Coastguard Worker 	for (; used_before; --used_before) {
160*33b1fccfSAndroid Build Coastguard Worker 		struct list_head *bt = bmgr->mapped_buckets[type] + used_before;
161*33b1fccfSAndroid Build Coastguard Worker 
162*33b1fccfSAndroid Build Coastguard Worker 		if (list_empty(bt))
163*33b1fccfSAndroid Build Coastguard Worker 			continue;
164*33b1fccfSAndroid Build Coastguard Worker 		cur = list_first_entry(bt, struct erofs_buffer_block,
165*33b1fccfSAndroid Build Coastguard Worker 				       mapped_list);
166*33b1fccfSAndroid Build Coastguard Worker 
167*33b1fccfSAndroid Build Coastguard Worker 		/* last mapped block can be expended, don't handle it here */
168*33b1fccfSAndroid Build Coastguard Worker 		if (list_next_entry(cur, list)->blkaddr == NULL_ADDR) {
169*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(cur != bmgr->last_mapped_block);
170*33b1fccfSAndroid Build Coastguard Worker 			continue;
171*33b1fccfSAndroid Build Coastguard Worker 		}
172*33b1fccfSAndroid Build Coastguard Worker 
173*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(cur->type != type);
174*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(cur->blkaddr == NULL_ADDR);
175*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(used_before != (cur->buffers.off & (blksiz - 1)));
176*33b1fccfSAndroid Build Coastguard Worker 
177*33b1fccfSAndroid Build Coastguard Worker 		ret = __erofs_battach(cur, NULL, size, alignsize,
178*33b1fccfSAndroid Build Coastguard Worker 				      required_ext + inline_ext, true);
179*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 0) {
180*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(1);
181*33b1fccfSAndroid Build Coastguard Worker 			continue;
182*33b1fccfSAndroid Build Coastguard Worker 		}
183*33b1fccfSAndroid Build Coastguard Worker 
184*33b1fccfSAndroid Build Coastguard Worker 		/* should contain all data in the current block */
185*33b1fccfSAndroid Build Coastguard Worker 		used = ret + required_ext + inline_ext;
186*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(used > blksiz);
187*33b1fccfSAndroid Build Coastguard Worker 
188*33b1fccfSAndroid Build Coastguard Worker 		bb = cur;
189*33b1fccfSAndroid Build Coastguard Worker 		usedmax = used;
190*33b1fccfSAndroid Build Coastguard Worker 		break;
191*33b1fccfSAndroid Build Coastguard Worker 	}
192*33b1fccfSAndroid Build Coastguard Worker 
193*33b1fccfSAndroid Build Coastguard Worker skip_mapped:
194*33b1fccfSAndroid Build Coastguard Worker 	/* try to start from the last mapped one, which can be expended */
195*33b1fccfSAndroid Build Coastguard Worker 	cur = bmgr->last_mapped_block;
196*33b1fccfSAndroid Build Coastguard Worker 	if (cur == &bmgr->blkh)
197*33b1fccfSAndroid Build Coastguard Worker 		cur = list_next_entry(cur, list);
198*33b1fccfSAndroid Build Coastguard Worker 	for (; cur != &bmgr->blkh; cur = list_next_entry(cur, list)) {
199*33b1fccfSAndroid Build Coastguard Worker 		used_before = cur->buffers.off & (blksiz - 1);
200*33b1fccfSAndroid Build Coastguard Worker 
201*33b1fccfSAndroid Build Coastguard Worker 		/* skip if buffer block is just full */
202*33b1fccfSAndroid Build Coastguard Worker 		if (!used_before)
203*33b1fccfSAndroid Build Coastguard Worker 			continue;
204*33b1fccfSAndroid Build Coastguard Worker 
205*33b1fccfSAndroid Build Coastguard Worker 		/* skip if the entry which has different type */
206*33b1fccfSAndroid Build Coastguard Worker 		if (cur->type != type)
207*33b1fccfSAndroid Build Coastguard Worker 			continue;
208*33b1fccfSAndroid Build Coastguard Worker 
209*33b1fccfSAndroid Build Coastguard Worker 		ret = __erofs_battach(cur, NULL, size, alignsize,
210*33b1fccfSAndroid Build Coastguard Worker 				      required_ext + inline_ext, true);
211*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 0)
212*33b1fccfSAndroid Build Coastguard Worker 			continue;
213*33b1fccfSAndroid Build Coastguard Worker 
214*33b1fccfSAndroid Build Coastguard Worker 		used = ((ret + required_ext) & (blksiz - 1)) + inline_ext;
215*33b1fccfSAndroid Build Coastguard Worker 
216*33b1fccfSAndroid Build Coastguard Worker 		/* should contain inline data in current block */
217*33b1fccfSAndroid Build Coastguard Worker 		if (used > blksiz)
218*33b1fccfSAndroid Build Coastguard Worker 			continue;
219*33b1fccfSAndroid Build Coastguard Worker 
220*33b1fccfSAndroid Build Coastguard Worker 		/*
221*33b1fccfSAndroid Build Coastguard Worker 		 * remaining should be smaller than before or
222*33b1fccfSAndroid Build Coastguard Worker 		 * larger than allocating a new buffer block
223*33b1fccfSAndroid Build Coastguard Worker 		 */
224*33b1fccfSAndroid Build Coastguard Worker 		if (used < used_before && used < used0)
225*33b1fccfSAndroid Build Coastguard Worker 			continue;
226*33b1fccfSAndroid Build Coastguard Worker 
227*33b1fccfSAndroid Build Coastguard Worker 		if (usedmax < used) {
228*33b1fccfSAndroid Build Coastguard Worker 			bb = cur;
229*33b1fccfSAndroid Build Coastguard Worker 			usedmax = used;
230*33b1fccfSAndroid Build Coastguard Worker 		}
231*33b1fccfSAndroid Build Coastguard Worker 	}
232*33b1fccfSAndroid Build Coastguard Worker 	*bbp = bb;
233*33b1fccfSAndroid Build Coastguard Worker 	return 0;
234*33b1fccfSAndroid Build Coastguard Worker }
235*33b1fccfSAndroid Build Coastguard Worker 
erofs_balloc(struct erofs_bufmgr * bmgr,int type,erofs_off_t size,unsigned int required_ext,unsigned int inline_ext)236*33b1fccfSAndroid Build Coastguard Worker struct erofs_buffer_head *erofs_balloc(struct erofs_bufmgr *bmgr,
237*33b1fccfSAndroid Build Coastguard Worker 				       int type, erofs_off_t size,
238*33b1fccfSAndroid Build Coastguard Worker 				       unsigned int required_ext,
239*33b1fccfSAndroid Build Coastguard Worker 				       unsigned int inline_ext)
240*33b1fccfSAndroid Build Coastguard Worker {
241*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_buffer_block *bb;
242*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_buffer_head *bh;
243*33b1fccfSAndroid Build Coastguard Worker 	unsigned int alignsize;
244*33b1fccfSAndroid Build Coastguard Worker 	int ret;
245*33b1fccfSAndroid Build Coastguard Worker 
246*33b1fccfSAndroid Build Coastguard Worker 	ret = get_alignsize(bmgr->sbi, type, &type);
247*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
248*33b1fccfSAndroid Build Coastguard Worker 		return ERR_PTR(ret);
249*33b1fccfSAndroid Build Coastguard Worker 
250*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(type < 0 || type > META);
251*33b1fccfSAndroid Build Coastguard Worker 	alignsize = ret;
252*33b1fccfSAndroid Build Coastguard Worker 
253*33b1fccfSAndroid Build Coastguard Worker 	/* try to find if we could reuse an allocated buffer block */
254*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_bfind_for_attach(bmgr, type, size, required_ext, inline_ext,
255*33b1fccfSAndroid Build Coastguard Worker 				     alignsize, &bb);
256*33b1fccfSAndroid Build Coastguard Worker 	if (ret)
257*33b1fccfSAndroid Build Coastguard Worker 		return ERR_PTR(ret);
258*33b1fccfSAndroid Build Coastguard Worker 
259*33b1fccfSAndroid Build Coastguard Worker 	if (bb) {
260*33b1fccfSAndroid Build Coastguard Worker 		bh = malloc(sizeof(struct erofs_buffer_head));
261*33b1fccfSAndroid Build Coastguard Worker 		if (!bh)
262*33b1fccfSAndroid Build Coastguard Worker 			return ERR_PTR(-ENOMEM);
263*33b1fccfSAndroid Build Coastguard Worker 	} else {
264*33b1fccfSAndroid Build Coastguard Worker 		/* get a new buffer block instead */
265*33b1fccfSAndroid Build Coastguard Worker 		bb = malloc(sizeof(struct erofs_buffer_block));
266*33b1fccfSAndroid Build Coastguard Worker 		if (!bb)
267*33b1fccfSAndroid Build Coastguard Worker 			return ERR_PTR(-ENOMEM);
268*33b1fccfSAndroid Build Coastguard Worker 
269*33b1fccfSAndroid Build Coastguard Worker 		bb->type = type;
270*33b1fccfSAndroid Build Coastguard Worker 		bb->blkaddr = NULL_ADDR;
271*33b1fccfSAndroid Build Coastguard Worker 		bb->buffers.off = 0;
272*33b1fccfSAndroid Build Coastguard Worker 		bb->buffers.fsprivate = bmgr;
273*33b1fccfSAndroid Build Coastguard Worker 		init_list_head(&bb->buffers.list);
274*33b1fccfSAndroid Build Coastguard Worker 		if (type == DATA)
275*33b1fccfSAndroid Build Coastguard Worker 			list_add(&bb->list,
276*33b1fccfSAndroid Build Coastguard Worker 				 &bmgr->last_mapped_block->list);
277*33b1fccfSAndroid Build Coastguard Worker 		else
278*33b1fccfSAndroid Build Coastguard Worker 			list_add_tail(&bb->list, &bmgr->blkh.list);
279*33b1fccfSAndroid Build Coastguard Worker 		init_list_head(&bb->mapped_list);
280*33b1fccfSAndroid Build Coastguard Worker 
281*33b1fccfSAndroid Build Coastguard Worker 		bh = malloc(sizeof(struct erofs_buffer_head));
282*33b1fccfSAndroid Build Coastguard Worker 		if (!bh) {
283*33b1fccfSAndroid Build Coastguard Worker 			free(bb);
284*33b1fccfSAndroid Build Coastguard Worker 			return ERR_PTR(-ENOMEM);
285*33b1fccfSAndroid Build Coastguard Worker 		}
286*33b1fccfSAndroid Build Coastguard Worker 	}
287*33b1fccfSAndroid Build Coastguard Worker 
288*33b1fccfSAndroid Build Coastguard Worker 	ret = __erofs_battach(bb, bh, size, alignsize,
289*33b1fccfSAndroid Build Coastguard Worker 			      required_ext + inline_ext, false);
290*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0) {
291*33b1fccfSAndroid Build Coastguard Worker 		free(bh);
292*33b1fccfSAndroid Build Coastguard Worker 		return ERR_PTR(ret);
293*33b1fccfSAndroid Build Coastguard Worker 	}
294*33b1fccfSAndroid Build Coastguard Worker 	return bh;
295*33b1fccfSAndroid Build Coastguard Worker }
296*33b1fccfSAndroid Build Coastguard Worker 
erofs_battach(struct erofs_buffer_head * bh,int type,unsigned int size)297*33b1fccfSAndroid Build Coastguard Worker struct erofs_buffer_head *erofs_battach(struct erofs_buffer_head *bh,
298*33b1fccfSAndroid Build Coastguard Worker 					int type, unsigned int size)
299*33b1fccfSAndroid Build Coastguard Worker {
300*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_buffer_block *const bb = bh->block;
301*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_bufmgr *bmgr = bb->buffers.fsprivate;
302*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_buffer_head *nbh;
303*33b1fccfSAndroid Build Coastguard Worker 	unsigned int alignsize;
304*33b1fccfSAndroid Build Coastguard Worker 	int ret = get_alignsize(bmgr->sbi, type, &type);
305*33b1fccfSAndroid Build Coastguard Worker 
306*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
307*33b1fccfSAndroid Build Coastguard Worker 		return ERR_PTR(ret);
308*33b1fccfSAndroid Build Coastguard Worker 	alignsize = ret;
309*33b1fccfSAndroid Build Coastguard Worker 
310*33b1fccfSAndroid Build Coastguard Worker 	/* should be the tail bh in the corresponding buffer block */
311*33b1fccfSAndroid Build Coastguard Worker 	if (bh->list.next != &bb->buffers.list)
312*33b1fccfSAndroid Build Coastguard Worker 		return ERR_PTR(-EINVAL);
313*33b1fccfSAndroid Build Coastguard Worker 
314*33b1fccfSAndroid Build Coastguard Worker 	nbh = malloc(sizeof(*nbh));
315*33b1fccfSAndroid Build Coastguard Worker 	if (!nbh)
316*33b1fccfSAndroid Build Coastguard Worker 		return ERR_PTR(-ENOMEM);
317*33b1fccfSAndroid Build Coastguard Worker 
318*33b1fccfSAndroid Build Coastguard Worker 	ret = __erofs_battach(bb, nbh, size, alignsize, 0, false);
319*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0) {
320*33b1fccfSAndroid Build Coastguard Worker 		free(nbh);
321*33b1fccfSAndroid Build Coastguard Worker 		return ERR_PTR(ret);
322*33b1fccfSAndroid Build Coastguard Worker 	}
323*33b1fccfSAndroid Build Coastguard Worker 	return nbh;
324*33b1fccfSAndroid Build Coastguard Worker }
325*33b1fccfSAndroid Build Coastguard Worker 
__erofs_mapbh(struct erofs_buffer_block * bb)326*33b1fccfSAndroid Build Coastguard Worker static erofs_blk_t __erofs_mapbh(struct erofs_buffer_block *bb)
327*33b1fccfSAndroid Build Coastguard Worker {
328*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_bufmgr *bmgr = bb->buffers.fsprivate;
329*33b1fccfSAndroid Build Coastguard Worker 	erofs_blk_t blkaddr;
330*33b1fccfSAndroid Build Coastguard Worker 
331*33b1fccfSAndroid Build Coastguard Worker 	if (bb->blkaddr == NULL_ADDR) {
332*33b1fccfSAndroid Build Coastguard Worker 		bb->blkaddr = bmgr->tail_blkaddr;
333*33b1fccfSAndroid Build Coastguard Worker 		bmgr->last_mapped_block = bb;
334*33b1fccfSAndroid Build Coastguard Worker 		erofs_bupdate_mapped(bb);
335*33b1fccfSAndroid Build Coastguard Worker 	}
336*33b1fccfSAndroid Build Coastguard Worker 
337*33b1fccfSAndroid Build Coastguard Worker 	blkaddr = bb->blkaddr + BLK_ROUND_UP(bmgr->sbi, bb->buffers.off);
338*33b1fccfSAndroid Build Coastguard Worker 	if (blkaddr > bmgr->tail_blkaddr)
339*33b1fccfSAndroid Build Coastguard Worker 		bmgr->tail_blkaddr = blkaddr;
340*33b1fccfSAndroid Build Coastguard Worker 	return blkaddr;
341*33b1fccfSAndroid Build Coastguard Worker }
342*33b1fccfSAndroid Build Coastguard Worker 
erofs_mapbh(struct erofs_bufmgr * bmgr,struct erofs_buffer_block * bb)343*33b1fccfSAndroid Build Coastguard Worker erofs_blk_t erofs_mapbh(struct erofs_bufmgr *bmgr,
344*33b1fccfSAndroid Build Coastguard Worker 			struct erofs_buffer_block *bb)
345*33b1fccfSAndroid Build Coastguard Worker {
346*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_buffer_block *t;
347*33b1fccfSAndroid Build Coastguard Worker 
348*33b1fccfSAndroid Build Coastguard Worker 	if (!bmgr)
349*33b1fccfSAndroid Build Coastguard Worker 		bmgr = bb->buffers.fsprivate;
350*33b1fccfSAndroid Build Coastguard Worker 	t = bmgr->last_mapped_block;
351*33b1fccfSAndroid Build Coastguard Worker 
352*33b1fccfSAndroid Build Coastguard Worker 	if (bb && bb->blkaddr != NULL_ADDR)
353*33b1fccfSAndroid Build Coastguard Worker 		return bb->blkaddr;
354*33b1fccfSAndroid Build Coastguard Worker 	do {
355*33b1fccfSAndroid Build Coastguard Worker 		t = list_next_entry(t, list);
356*33b1fccfSAndroid Build Coastguard Worker 		if (t == &bmgr->blkh)
357*33b1fccfSAndroid Build Coastguard Worker 			break;
358*33b1fccfSAndroid Build Coastguard Worker 
359*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(t->blkaddr != NULL_ADDR);
360*33b1fccfSAndroid Build Coastguard Worker 		(void)__erofs_mapbh(t);
361*33b1fccfSAndroid Build Coastguard Worker 	} while (t != bb);
362*33b1fccfSAndroid Build Coastguard Worker 	return bmgr->tail_blkaddr;
363*33b1fccfSAndroid Build Coastguard Worker }
364*33b1fccfSAndroid Build Coastguard Worker 
erofs_bfree(struct erofs_buffer_block * bb)365*33b1fccfSAndroid Build Coastguard Worker static void erofs_bfree(struct erofs_buffer_block *bb)
366*33b1fccfSAndroid Build Coastguard Worker {
367*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_bufmgr *bmgr = bb->buffers.fsprivate;
368*33b1fccfSAndroid Build Coastguard Worker 
369*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(!list_empty(&bb->buffers.list));
370*33b1fccfSAndroid Build Coastguard Worker 
371*33b1fccfSAndroid Build Coastguard Worker 	if (bb == bmgr->last_mapped_block)
372*33b1fccfSAndroid Build Coastguard Worker 		bmgr->last_mapped_block = list_prev_entry(bb, list);
373*33b1fccfSAndroid Build Coastguard Worker 
374*33b1fccfSAndroid Build Coastguard Worker 	list_del(&bb->mapped_list);
375*33b1fccfSAndroid Build Coastguard Worker 	list_del(&bb->list);
376*33b1fccfSAndroid Build Coastguard Worker 	free(bb);
377*33b1fccfSAndroid Build Coastguard Worker }
378*33b1fccfSAndroid Build Coastguard Worker 
erofs_bflush(struct erofs_bufmgr * bmgr,struct erofs_buffer_block * bb)379*33b1fccfSAndroid Build Coastguard Worker int erofs_bflush(struct erofs_bufmgr *bmgr,
380*33b1fccfSAndroid Build Coastguard Worker 		 struct erofs_buffer_block *bb)
381*33b1fccfSAndroid Build Coastguard Worker {
382*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = bmgr->sbi;
383*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int blksiz = erofs_blksiz(sbi);
384*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_buffer_block *p, *n;
385*33b1fccfSAndroid Build Coastguard Worker 	erofs_blk_t blkaddr;
386*33b1fccfSAndroid Build Coastguard Worker 
387*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry_safe(p, n, &bmgr->blkh.list, list) {
388*33b1fccfSAndroid Build Coastguard Worker 		struct erofs_buffer_head *bh, *nbh;
389*33b1fccfSAndroid Build Coastguard Worker 		unsigned int padding;
390*33b1fccfSAndroid Build Coastguard Worker 		bool skip = false;
391*33b1fccfSAndroid Build Coastguard Worker 		int ret;
392*33b1fccfSAndroid Build Coastguard Worker 
393*33b1fccfSAndroid Build Coastguard Worker 		if (p == bb)
394*33b1fccfSAndroid Build Coastguard Worker 			break;
395*33b1fccfSAndroid Build Coastguard Worker 
396*33b1fccfSAndroid Build Coastguard Worker 		blkaddr = __erofs_mapbh(p);
397*33b1fccfSAndroid Build Coastguard Worker 
398*33b1fccfSAndroid Build Coastguard Worker 		list_for_each_entry_safe(bh, nbh, &p->buffers.list, list) {
399*33b1fccfSAndroid Build Coastguard Worker 			if (bh->op == &erofs_skip_write_bhops) {
400*33b1fccfSAndroid Build Coastguard Worker 				skip = true;
401*33b1fccfSAndroid Build Coastguard Worker 				continue;
402*33b1fccfSAndroid Build Coastguard Worker 			}
403*33b1fccfSAndroid Build Coastguard Worker 
404*33b1fccfSAndroid Build Coastguard Worker 			/* flush and remove bh */
405*33b1fccfSAndroid Build Coastguard Worker 			ret = bh->op->flush(bh);
406*33b1fccfSAndroid Build Coastguard Worker 			if (ret < 0)
407*33b1fccfSAndroid Build Coastguard Worker 				return ret;
408*33b1fccfSAndroid Build Coastguard Worker 		}
409*33b1fccfSAndroid Build Coastguard Worker 
410*33b1fccfSAndroid Build Coastguard Worker 		if (skip)
411*33b1fccfSAndroid Build Coastguard Worker 			continue;
412*33b1fccfSAndroid Build Coastguard Worker 
413*33b1fccfSAndroid Build Coastguard Worker 		padding = blksiz - (p->buffers.off & (blksiz - 1));
414*33b1fccfSAndroid Build Coastguard Worker 		if (padding != blksiz)
415*33b1fccfSAndroid Build Coastguard Worker 			erofs_dev_fillzero(sbi, erofs_pos(sbi, blkaddr) - padding,
416*33b1fccfSAndroid Build Coastguard Worker 					   padding, true);
417*33b1fccfSAndroid Build Coastguard Worker 
418*33b1fccfSAndroid Build Coastguard Worker 		if (p->type != DATA)
419*33b1fccfSAndroid Build Coastguard Worker 			bmgr->metablkcnt +=
420*33b1fccfSAndroid Build Coastguard Worker 				BLK_ROUND_UP(sbi, p->buffers.off);
421*33b1fccfSAndroid Build Coastguard Worker 		erofs_dbg("block %u to %u flushed", p->blkaddr, blkaddr - 1);
422*33b1fccfSAndroid Build Coastguard Worker 		erofs_bfree(p);
423*33b1fccfSAndroid Build Coastguard Worker 	}
424*33b1fccfSAndroid Build Coastguard Worker 	return 0;
425*33b1fccfSAndroid Build Coastguard Worker }
426*33b1fccfSAndroid Build Coastguard Worker 
erofs_bdrop(struct erofs_buffer_head * bh,bool tryrevoke)427*33b1fccfSAndroid Build Coastguard Worker void erofs_bdrop(struct erofs_buffer_head *bh, bool tryrevoke)
428*33b1fccfSAndroid Build Coastguard Worker {
429*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_buffer_block *const bb = bh->block;
430*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_bufmgr *bmgr = bb->buffers.fsprivate;
431*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = bmgr->sbi;
432*33b1fccfSAndroid Build Coastguard Worker 	const erofs_blk_t blkaddr = bh->block->blkaddr;
433*33b1fccfSAndroid Build Coastguard Worker 	bool rollback = false;
434*33b1fccfSAndroid Build Coastguard Worker 
435*33b1fccfSAndroid Build Coastguard Worker 	/* tail_blkaddr could be rolled back after revoking all bhs */
436*33b1fccfSAndroid Build Coastguard Worker 	if (tryrevoke && blkaddr != NULL_ADDR &&
437*33b1fccfSAndroid Build Coastguard Worker 	    bmgr->tail_blkaddr == blkaddr + BLK_ROUND_UP(sbi, bb->buffers.off))
438*33b1fccfSAndroid Build Coastguard Worker 		rollback = true;
439*33b1fccfSAndroid Build Coastguard Worker 
440*33b1fccfSAndroid Build Coastguard Worker 	bh->op = &erofs_drop_directly_bhops;
441*33b1fccfSAndroid Build Coastguard Worker 	erofs_bh_flush_generic_end(bh);
442*33b1fccfSAndroid Build Coastguard Worker 
443*33b1fccfSAndroid Build Coastguard Worker 	if (!list_empty(&bb->buffers.list))
444*33b1fccfSAndroid Build Coastguard Worker 		return;
445*33b1fccfSAndroid Build Coastguard Worker 
446*33b1fccfSAndroid Build Coastguard Worker 	if (!rollback && bb->type != DATA)
447*33b1fccfSAndroid Build Coastguard Worker 		bmgr->metablkcnt += BLK_ROUND_UP(sbi, bb->buffers.off);
448*33b1fccfSAndroid Build Coastguard Worker 	erofs_bfree(bb);
449*33b1fccfSAndroid Build Coastguard Worker 	if (rollback)
450*33b1fccfSAndroid Build Coastguard Worker 		bmgr->tail_blkaddr = blkaddr;
451*33b1fccfSAndroid Build Coastguard Worker }
452*33b1fccfSAndroid Build Coastguard Worker 
erofs_total_metablocks(struct erofs_bufmgr * bmgr)453*33b1fccfSAndroid Build Coastguard Worker erofs_blk_t erofs_total_metablocks(struct erofs_bufmgr *bmgr)
454*33b1fccfSAndroid Build Coastguard Worker {
455*33b1fccfSAndroid Build Coastguard Worker 	return bmgr->metablkcnt;
456*33b1fccfSAndroid Build Coastguard Worker }
457*33b1fccfSAndroid Build Coastguard Worker 
erofs_buffer_exit(struct erofs_bufmgr * bmgr)458*33b1fccfSAndroid Build Coastguard Worker void erofs_buffer_exit(struct erofs_bufmgr *bmgr)
459*33b1fccfSAndroid Build Coastguard Worker {
460*33b1fccfSAndroid Build Coastguard Worker 	free(bmgr);
461*33b1fccfSAndroid Build Coastguard Worker }
462