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