1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2000-2005 Silicon Graphics, Inc.
4*4882a593Smuzhiyun * All Rights Reserved.
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun #include "xfs.h"
7*4882a593Smuzhiyun #include "xfs_fs.h"
8*4882a593Smuzhiyun #include "xfs_shared.h"
9*4882a593Smuzhiyun #include "xfs_format.h"
10*4882a593Smuzhiyun #include "xfs_log_format.h"
11*4882a593Smuzhiyun #include "xfs_trans_resv.h"
12*4882a593Smuzhiyun #include "xfs_bit.h"
13*4882a593Smuzhiyun #include "xfs_mount.h"
14*4882a593Smuzhiyun #include "xfs_inode.h"
15*4882a593Smuzhiyun #include "xfs_bmap.h"
16*4882a593Smuzhiyun #include "xfs_trans.h"
17*4882a593Smuzhiyun #include "xfs_rtalloc.h"
18*4882a593Smuzhiyun #include "xfs_error.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun /*
21*4882a593Smuzhiyun * Realtime allocator bitmap functions shared with userspace.
22*4882a593Smuzhiyun */
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun /*
25*4882a593Smuzhiyun * Real time buffers need verifiers to avoid runtime warnings during IO.
26*4882a593Smuzhiyun * We don't have anything to verify, however, so these are just dummy
27*4882a593Smuzhiyun * operations.
28*4882a593Smuzhiyun */
29*4882a593Smuzhiyun static void
xfs_rtbuf_verify_read(struct xfs_buf * bp)30*4882a593Smuzhiyun xfs_rtbuf_verify_read(
31*4882a593Smuzhiyun struct xfs_buf *bp)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun return;
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun static void
xfs_rtbuf_verify_write(struct xfs_buf * bp)37*4882a593Smuzhiyun xfs_rtbuf_verify_write(
38*4882a593Smuzhiyun struct xfs_buf *bp)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun return;
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun const struct xfs_buf_ops xfs_rtbuf_ops = {
44*4882a593Smuzhiyun .name = "rtbuf",
45*4882a593Smuzhiyun .verify_read = xfs_rtbuf_verify_read,
46*4882a593Smuzhiyun .verify_write = xfs_rtbuf_verify_write,
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun /*
50*4882a593Smuzhiyun * Get a buffer for the bitmap or summary file block specified.
51*4882a593Smuzhiyun * The buffer is returned read and locked.
52*4882a593Smuzhiyun */
53*4882a593Smuzhiyun int
xfs_rtbuf_get(xfs_mount_t * mp,xfs_trans_t * tp,xfs_rtblock_t block,int issum,xfs_buf_t ** bpp)54*4882a593Smuzhiyun xfs_rtbuf_get(
55*4882a593Smuzhiyun xfs_mount_t *mp, /* file system mount structure */
56*4882a593Smuzhiyun xfs_trans_t *tp, /* transaction pointer */
57*4882a593Smuzhiyun xfs_rtblock_t block, /* block number in bitmap or summary */
58*4882a593Smuzhiyun int issum, /* is summary not bitmap */
59*4882a593Smuzhiyun xfs_buf_t **bpp) /* output: buffer for the block */
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun xfs_buf_t *bp; /* block buffer, result */
62*4882a593Smuzhiyun xfs_inode_t *ip; /* bitmap or summary inode */
63*4882a593Smuzhiyun xfs_bmbt_irec_t map;
64*4882a593Smuzhiyun int nmap = 1;
65*4882a593Smuzhiyun int error; /* error value */
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun ip = issum ? mp->m_rsumip : mp->m_rbmip;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun error = xfs_bmapi_read(ip, block, 1, &map, &nmap, 0);
70*4882a593Smuzhiyun if (error)
71*4882a593Smuzhiyun return error;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun if (XFS_IS_CORRUPT(mp, nmap == 0 || !xfs_bmap_is_written_extent(&map)))
74*4882a593Smuzhiyun return -EFSCORRUPTED;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun ASSERT(map.br_startblock != NULLFSBLOCK);
77*4882a593Smuzhiyun error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
78*4882a593Smuzhiyun XFS_FSB_TO_DADDR(mp, map.br_startblock),
79*4882a593Smuzhiyun mp->m_bsize, 0, &bp, &xfs_rtbuf_ops);
80*4882a593Smuzhiyun if (error)
81*4882a593Smuzhiyun return error;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun xfs_trans_buf_set_type(tp, bp, issum ? XFS_BLFT_RTSUMMARY_BUF
84*4882a593Smuzhiyun : XFS_BLFT_RTBITMAP_BUF);
85*4882a593Smuzhiyun *bpp = bp;
86*4882a593Smuzhiyun return 0;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun /*
90*4882a593Smuzhiyun * Searching backward from start to limit, find the first block whose
91*4882a593Smuzhiyun * allocated/free state is different from start's.
92*4882a593Smuzhiyun */
93*4882a593Smuzhiyun int
xfs_rtfind_back(xfs_mount_t * mp,xfs_trans_t * tp,xfs_rtblock_t start,xfs_rtblock_t limit,xfs_rtblock_t * rtblock)94*4882a593Smuzhiyun xfs_rtfind_back(
95*4882a593Smuzhiyun xfs_mount_t *mp, /* file system mount point */
96*4882a593Smuzhiyun xfs_trans_t *tp, /* transaction pointer */
97*4882a593Smuzhiyun xfs_rtblock_t start, /* starting block to look at */
98*4882a593Smuzhiyun xfs_rtblock_t limit, /* last block to look at */
99*4882a593Smuzhiyun xfs_rtblock_t *rtblock) /* out: start block found */
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun xfs_rtword_t *b; /* current word in buffer */
102*4882a593Smuzhiyun int bit; /* bit number in the word */
103*4882a593Smuzhiyun xfs_rtblock_t block; /* bitmap block number */
104*4882a593Smuzhiyun xfs_buf_t *bp; /* buf for the block */
105*4882a593Smuzhiyun xfs_rtword_t *bufp; /* starting word in buffer */
106*4882a593Smuzhiyun int error; /* error value */
107*4882a593Smuzhiyun xfs_rtblock_t firstbit; /* first useful bit in the word */
108*4882a593Smuzhiyun xfs_rtblock_t i; /* current bit number rel. to start */
109*4882a593Smuzhiyun xfs_rtblock_t len; /* length of inspected area */
110*4882a593Smuzhiyun xfs_rtword_t mask; /* mask of relevant bits for value */
111*4882a593Smuzhiyun xfs_rtword_t want; /* mask for "good" values */
112*4882a593Smuzhiyun xfs_rtword_t wdiff; /* difference from wanted value */
113*4882a593Smuzhiyun int word; /* word number in the buffer */
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun /*
116*4882a593Smuzhiyun * Compute and read in starting bitmap block for starting block.
117*4882a593Smuzhiyun */
118*4882a593Smuzhiyun block = XFS_BITTOBLOCK(mp, start);
119*4882a593Smuzhiyun error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
120*4882a593Smuzhiyun if (error) {
121*4882a593Smuzhiyun return error;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun bufp = bp->b_addr;
124*4882a593Smuzhiyun /*
125*4882a593Smuzhiyun * Get the first word's index & point to it.
126*4882a593Smuzhiyun */
127*4882a593Smuzhiyun word = XFS_BITTOWORD(mp, start);
128*4882a593Smuzhiyun b = &bufp[word];
129*4882a593Smuzhiyun bit = (int)(start & (XFS_NBWORD - 1));
130*4882a593Smuzhiyun len = start - limit + 1;
131*4882a593Smuzhiyun /*
132*4882a593Smuzhiyun * Compute match value, based on the bit at start: if 1 (free)
133*4882a593Smuzhiyun * then all-ones, else all-zeroes.
134*4882a593Smuzhiyun */
135*4882a593Smuzhiyun want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0;
136*4882a593Smuzhiyun /*
137*4882a593Smuzhiyun * If the starting position is not word-aligned, deal with the
138*4882a593Smuzhiyun * partial word.
139*4882a593Smuzhiyun */
140*4882a593Smuzhiyun if (bit < XFS_NBWORD - 1) {
141*4882a593Smuzhiyun /*
142*4882a593Smuzhiyun * Calculate first (leftmost) bit number to look at,
143*4882a593Smuzhiyun * and mask for all the relevant bits in this word.
144*4882a593Smuzhiyun */
145*4882a593Smuzhiyun firstbit = XFS_RTMAX((xfs_srtblock_t)(bit - len + 1), 0);
146*4882a593Smuzhiyun mask = (((xfs_rtword_t)1 << (bit - firstbit + 1)) - 1) <<
147*4882a593Smuzhiyun firstbit;
148*4882a593Smuzhiyun /*
149*4882a593Smuzhiyun * Calculate the difference between the value there
150*4882a593Smuzhiyun * and what we're looking for.
151*4882a593Smuzhiyun */
152*4882a593Smuzhiyun if ((wdiff = (*b ^ want) & mask)) {
153*4882a593Smuzhiyun /*
154*4882a593Smuzhiyun * Different. Mark where we are and return.
155*4882a593Smuzhiyun */
156*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
157*4882a593Smuzhiyun i = bit - XFS_RTHIBIT(wdiff);
158*4882a593Smuzhiyun *rtblock = start - i + 1;
159*4882a593Smuzhiyun return 0;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun i = bit - firstbit + 1;
162*4882a593Smuzhiyun /*
163*4882a593Smuzhiyun * Go on to previous block if that's where the previous word is
164*4882a593Smuzhiyun * and we need the previous word.
165*4882a593Smuzhiyun */
166*4882a593Smuzhiyun if (--word == -1 && i < len) {
167*4882a593Smuzhiyun /*
168*4882a593Smuzhiyun * If done with this block, get the previous one.
169*4882a593Smuzhiyun */
170*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
171*4882a593Smuzhiyun error = xfs_rtbuf_get(mp, tp, --block, 0, &bp);
172*4882a593Smuzhiyun if (error) {
173*4882a593Smuzhiyun return error;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun bufp = bp->b_addr;
176*4882a593Smuzhiyun word = XFS_BLOCKWMASK(mp);
177*4882a593Smuzhiyun b = &bufp[word];
178*4882a593Smuzhiyun } else {
179*4882a593Smuzhiyun /*
180*4882a593Smuzhiyun * Go on to the previous word in the buffer.
181*4882a593Smuzhiyun */
182*4882a593Smuzhiyun b--;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun } else {
185*4882a593Smuzhiyun /*
186*4882a593Smuzhiyun * Starting on a word boundary, no partial word.
187*4882a593Smuzhiyun */
188*4882a593Smuzhiyun i = 0;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun /*
191*4882a593Smuzhiyun * Loop over whole words in buffers. When we use up one buffer
192*4882a593Smuzhiyun * we move on to the previous one.
193*4882a593Smuzhiyun */
194*4882a593Smuzhiyun while (len - i >= XFS_NBWORD) {
195*4882a593Smuzhiyun /*
196*4882a593Smuzhiyun * Compute difference between actual and desired value.
197*4882a593Smuzhiyun */
198*4882a593Smuzhiyun if ((wdiff = *b ^ want)) {
199*4882a593Smuzhiyun /*
200*4882a593Smuzhiyun * Different, mark where we are and return.
201*4882a593Smuzhiyun */
202*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
203*4882a593Smuzhiyun i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff);
204*4882a593Smuzhiyun *rtblock = start - i + 1;
205*4882a593Smuzhiyun return 0;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun i += XFS_NBWORD;
208*4882a593Smuzhiyun /*
209*4882a593Smuzhiyun * Go on to previous block if that's where the previous word is
210*4882a593Smuzhiyun * and we need the previous word.
211*4882a593Smuzhiyun */
212*4882a593Smuzhiyun if (--word == -1 && i < len) {
213*4882a593Smuzhiyun /*
214*4882a593Smuzhiyun * If done with this block, get the previous one.
215*4882a593Smuzhiyun */
216*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
217*4882a593Smuzhiyun error = xfs_rtbuf_get(mp, tp, --block, 0, &bp);
218*4882a593Smuzhiyun if (error) {
219*4882a593Smuzhiyun return error;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun bufp = bp->b_addr;
222*4882a593Smuzhiyun word = XFS_BLOCKWMASK(mp);
223*4882a593Smuzhiyun b = &bufp[word];
224*4882a593Smuzhiyun } else {
225*4882a593Smuzhiyun /*
226*4882a593Smuzhiyun * Go on to the previous word in the buffer.
227*4882a593Smuzhiyun */
228*4882a593Smuzhiyun b--;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun /*
232*4882a593Smuzhiyun * If not ending on a word boundary, deal with the last
233*4882a593Smuzhiyun * (partial) word.
234*4882a593Smuzhiyun */
235*4882a593Smuzhiyun if (len - i) {
236*4882a593Smuzhiyun /*
237*4882a593Smuzhiyun * Calculate first (leftmost) bit number to look at,
238*4882a593Smuzhiyun * and mask for all the relevant bits in this word.
239*4882a593Smuzhiyun */
240*4882a593Smuzhiyun firstbit = XFS_NBWORD - (len - i);
241*4882a593Smuzhiyun mask = (((xfs_rtword_t)1 << (len - i)) - 1) << firstbit;
242*4882a593Smuzhiyun /*
243*4882a593Smuzhiyun * Compute difference between actual and desired value.
244*4882a593Smuzhiyun */
245*4882a593Smuzhiyun if ((wdiff = (*b ^ want) & mask)) {
246*4882a593Smuzhiyun /*
247*4882a593Smuzhiyun * Different, mark where we are and return.
248*4882a593Smuzhiyun */
249*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
250*4882a593Smuzhiyun i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff);
251*4882a593Smuzhiyun *rtblock = start - i + 1;
252*4882a593Smuzhiyun return 0;
253*4882a593Smuzhiyun } else
254*4882a593Smuzhiyun i = len;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun /*
257*4882a593Smuzhiyun * No match, return that we scanned the whole area.
258*4882a593Smuzhiyun */
259*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
260*4882a593Smuzhiyun *rtblock = start - i + 1;
261*4882a593Smuzhiyun return 0;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun /*
265*4882a593Smuzhiyun * Searching forward from start to limit, find the first block whose
266*4882a593Smuzhiyun * allocated/free state is different from start's.
267*4882a593Smuzhiyun */
268*4882a593Smuzhiyun int
xfs_rtfind_forw(xfs_mount_t * mp,xfs_trans_t * tp,xfs_rtblock_t start,xfs_rtblock_t limit,xfs_rtblock_t * rtblock)269*4882a593Smuzhiyun xfs_rtfind_forw(
270*4882a593Smuzhiyun xfs_mount_t *mp, /* file system mount point */
271*4882a593Smuzhiyun xfs_trans_t *tp, /* transaction pointer */
272*4882a593Smuzhiyun xfs_rtblock_t start, /* starting block to look at */
273*4882a593Smuzhiyun xfs_rtblock_t limit, /* last block to look at */
274*4882a593Smuzhiyun xfs_rtblock_t *rtblock) /* out: start block found */
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun xfs_rtword_t *b; /* current word in buffer */
277*4882a593Smuzhiyun int bit; /* bit number in the word */
278*4882a593Smuzhiyun xfs_rtblock_t block; /* bitmap block number */
279*4882a593Smuzhiyun xfs_buf_t *bp; /* buf for the block */
280*4882a593Smuzhiyun xfs_rtword_t *bufp; /* starting word in buffer */
281*4882a593Smuzhiyun int error; /* error value */
282*4882a593Smuzhiyun xfs_rtblock_t i; /* current bit number rel. to start */
283*4882a593Smuzhiyun xfs_rtblock_t lastbit; /* last useful bit in the word */
284*4882a593Smuzhiyun xfs_rtblock_t len; /* length of inspected area */
285*4882a593Smuzhiyun xfs_rtword_t mask; /* mask of relevant bits for value */
286*4882a593Smuzhiyun xfs_rtword_t want; /* mask for "good" values */
287*4882a593Smuzhiyun xfs_rtword_t wdiff; /* difference from wanted value */
288*4882a593Smuzhiyun int word; /* word number in the buffer */
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun /*
291*4882a593Smuzhiyun * Compute and read in starting bitmap block for starting block.
292*4882a593Smuzhiyun */
293*4882a593Smuzhiyun block = XFS_BITTOBLOCK(mp, start);
294*4882a593Smuzhiyun error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
295*4882a593Smuzhiyun if (error) {
296*4882a593Smuzhiyun return error;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun bufp = bp->b_addr;
299*4882a593Smuzhiyun /*
300*4882a593Smuzhiyun * Get the first word's index & point to it.
301*4882a593Smuzhiyun */
302*4882a593Smuzhiyun word = XFS_BITTOWORD(mp, start);
303*4882a593Smuzhiyun b = &bufp[word];
304*4882a593Smuzhiyun bit = (int)(start & (XFS_NBWORD - 1));
305*4882a593Smuzhiyun len = limit - start + 1;
306*4882a593Smuzhiyun /*
307*4882a593Smuzhiyun * Compute match value, based on the bit at start: if 1 (free)
308*4882a593Smuzhiyun * then all-ones, else all-zeroes.
309*4882a593Smuzhiyun */
310*4882a593Smuzhiyun want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0;
311*4882a593Smuzhiyun /*
312*4882a593Smuzhiyun * If the starting position is not word-aligned, deal with the
313*4882a593Smuzhiyun * partial word.
314*4882a593Smuzhiyun */
315*4882a593Smuzhiyun if (bit) {
316*4882a593Smuzhiyun /*
317*4882a593Smuzhiyun * Calculate last (rightmost) bit number to look at,
318*4882a593Smuzhiyun * and mask for all the relevant bits in this word.
319*4882a593Smuzhiyun */
320*4882a593Smuzhiyun lastbit = XFS_RTMIN(bit + len, XFS_NBWORD);
321*4882a593Smuzhiyun mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit;
322*4882a593Smuzhiyun /*
323*4882a593Smuzhiyun * Calculate the difference between the value there
324*4882a593Smuzhiyun * and what we're looking for.
325*4882a593Smuzhiyun */
326*4882a593Smuzhiyun if ((wdiff = (*b ^ want) & mask)) {
327*4882a593Smuzhiyun /*
328*4882a593Smuzhiyun * Different. Mark where we are and return.
329*4882a593Smuzhiyun */
330*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
331*4882a593Smuzhiyun i = XFS_RTLOBIT(wdiff) - bit;
332*4882a593Smuzhiyun *rtblock = start + i - 1;
333*4882a593Smuzhiyun return 0;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun i = lastbit - bit;
336*4882a593Smuzhiyun /*
337*4882a593Smuzhiyun * Go on to next block if that's where the next word is
338*4882a593Smuzhiyun * and we need the next word.
339*4882a593Smuzhiyun */
340*4882a593Smuzhiyun if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
341*4882a593Smuzhiyun /*
342*4882a593Smuzhiyun * If done with this block, get the previous one.
343*4882a593Smuzhiyun */
344*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
345*4882a593Smuzhiyun error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
346*4882a593Smuzhiyun if (error) {
347*4882a593Smuzhiyun return error;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun b = bufp = bp->b_addr;
350*4882a593Smuzhiyun word = 0;
351*4882a593Smuzhiyun } else {
352*4882a593Smuzhiyun /*
353*4882a593Smuzhiyun * Go on to the previous word in the buffer.
354*4882a593Smuzhiyun */
355*4882a593Smuzhiyun b++;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun } else {
358*4882a593Smuzhiyun /*
359*4882a593Smuzhiyun * Starting on a word boundary, no partial word.
360*4882a593Smuzhiyun */
361*4882a593Smuzhiyun i = 0;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun /*
364*4882a593Smuzhiyun * Loop over whole words in buffers. When we use up one buffer
365*4882a593Smuzhiyun * we move on to the next one.
366*4882a593Smuzhiyun */
367*4882a593Smuzhiyun while (len - i >= XFS_NBWORD) {
368*4882a593Smuzhiyun /*
369*4882a593Smuzhiyun * Compute difference between actual and desired value.
370*4882a593Smuzhiyun */
371*4882a593Smuzhiyun if ((wdiff = *b ^ want)) {
372*4882a593Smuzhiyun /*
373*4882a593Smuzhiyun * Different, mark where we are and return.
374*4882a593Smuzhiyun */
375*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
376*4882a593Smuzhiyun i += XFS_RTLOBIT(wdiff);
377*4882a593Smuzhiyun *rtblock = start + i - 1;
378*4882a593Smuzhiyun return 0;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun i += XFS_NBWORD;
381*4882a593Smuzhiyun /*
382*4882a593Smuzhiyun * Go on to next block if that's where the next word is
383*4882a593Smuzhiyun * and we need the next word.
384*4882a593Smuzhiyun */
385*4882a593Smuzhiyun if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
386*4882a593Smuzhiyun /*
387*4882a593Smuzhiyun * If done with this block, get the next one.
388*4882a593Smuzhiyun */
389*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
390*4882a593Smuzhiyun error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
391*4882a593Smuzhiyun if (error) {
392*4882a593Smuzhiyun return error;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun b = bufp = bp->b_addr;
395*4882a593Smuzhiyun word = 0;
396*4882a593Smuzhiyun } else {
397*4882a593Smuzhiyun /*
398*4882a593Smuzhiyun * Go on to the next word in the buffer.
399*4882a593Smuzhiyun */
400*4882a593Smuzhiyun b++;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun /*
404*4882a593Smuzhiyun * If not ending on a word boundary, deal with the last
405*4882a593Smuzhiyun * (partial) word.
406*4882a593Smuzhiyun */
407*4882a593Smuzhiyun if ((lastbit = len - i)) {
408*4882a593Smuzhiyun /*
409*4882a593Smuzhiyun * Calculate mask for all the relevant bits in this word.
410*4882a593Smuzhiyun */
411*4882a593Smuzhiyun mask = ((xfs_rtword_t)1 << lastbit) - 1;
412*4882a593Smuzhiyun /*
413*4882a593Smuzhiyun * Compute difference between actual and desired value.
414*4882a593Smuzhiyun */
415*4882a593Smuzhiyun if ((wdiff = (*b ^ want) & mask)) {
416*4882a593Smuzhiyun /*
417*4882a593Smuzhiyun * Different, mark where we are and return.
418*4882a593Smuzhiyun */
419*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
420*4882a593Smuzhiyun i += XFS_RTLOBIT(wdiff);
421*4882a593Smuzhiyun *rtblock = start + i - 1;
422*4882a593Smuzhiyun return 0;
423*4882a593Smuzhiyun } else
424*4882a593Smuzhiyun i = len;
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun /*
427*4882a593Smuzhiyun * No match, return that we scanned the whole area.
428*4882a593Smuzhiyun */
429*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
430*4882a593Smuzhiyun *rtblock = start + i - 1;
431*4882a593Smuzhiyun return 0;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun /*
435*4882a593Smuzhiyun * Read and/or modify the summary information for a given extent size,
436*4882a593Smuzhiyun * bitmap block combination.
437*4882a593Smuzhiyun * Keeps track of a current summary block, so we don't keep reading
438*4882a593Smuzhiyun * it from the buffer cache.
439*4882a593Smuzhiyun *
440*4882a593Smuzhiyun * Summary information is returned in *sum if specified.
441*4882a593Smuzhiyun * If no delta is specified, returns summary only.
442*4882a593Smuzhiyun */
443*4882a593Smuzhiyun int
xfs_rtmodify_summary_int(xfs_mount_t * mp,xfs_trans_t * tp,int log,xfs_rtblock_t bbno,int delta,xfs_buf_t ** rbpp,xfs_fsblock_t * rsb,xfs_suminfo_t * sum)444*4882a593Smuzhiyun xfs_rtmodify_summary_int(
445*4882a593Smuzhiyun xfs_mount_t *mp, /* file system mount structure */
446*4882a593Smuzhiyun xfs_trans_t *tp, /* transaction pointer */
447*4882a593Smuzhiyun int log, /* log2 of extent size */
448*4882a593Smuzhiyun xfs_rtblock_t bbno, /* bitmap block number */
449*4882a593Smuzhiyun int delta, /* change to make to summary info */
450*4882a593Smuzhiyun xfs_buf_t **rbpp, /* in/out: summary block buffer */
451*4882a593Smuzhiyun xfs_fsblock_t *rsb, /* in/out: summary block number */
452*4882a593Smuzhiyun xfs_suminfo_t *sum) /* out: summary info for this block */
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun xfs_buf_t *bp; /* buffer for the summary block */
455*4882a593Smuzhiyun int error; /* error value */
456*4882a593Smuzhiyun xfs_fsblock_t sb; /* summary fsblock */
457*4882a593Smuzhiyun int so; /* index into the summary file */
458*4882a593Smuzhiyun xfs_suminfo_t *sp; /* pointer to returned data */
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun /*
461*4882a593Smuzhiyun * Compute entry number in the summary file.
462*4882a593Smuzhiyun */
463*4882a593Smuzhiyun so = XFS_SUMOFFS(mp, log, bbno);
464*4882a593Smuzhiyun /*
465*4882a593Smuzhiyun * Compute the block number in the summary file.
466*4882a593Smuzhiyun */
467*4882a593Smuzhiyun sb = XFS_SUMOFFSTOBLOCK(mp, so);
468*4882a593Smuzhiyun /*
469*4882a593Smuzhiyun * If we have an old buffer, and the block number matches, use that.
470*4882a593Smuzhiyun */
471*4882a593Smuzhiyun if (*rbpp && *rsb == sb)
472*4882a593Smuzhiyun bp = *rbpp;
473*4882a593Smuzhiyun /*
474*4882a593Smuzhiyun * Otherwise we have to get the buffer.
475*4882a593Smuzhiyun */
476*4882a593Smuzhiyun else {
477*4882a593Smuzhiyun /*
478*4882a593Smuzhiyun * If there was an old one, get rid of it first.
479*4882a593Smuzhiyun */
480*4882a593Smuzhiyun if (*rbpp)
481*4882a593Smuzhiyun xfs_trans_brelse(tp, *rbpp);
482*4882a593Smuzhiyun error = xfs_rtbuf_get(mp, tp, sb, 1, &bp);
483*4882a593Smuzhiyun if (error) {
484*4882a593Smuzhiyun return error;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun /*
487*4882a593Smuzhiyun * Remember this buffer and block for the next call.
488*4882a593Smuzhiyun */
489*4882a593Smuzhiyun *rbpp = bp;
490*4882a593Smuzhiyun *rsb = sb;
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun /*
493*4882a593Smuzhiyun * Point to the summary information, modify/log it, and/or copy it out.
494*4882a593Smuzhiyun */
495*4882a593Smuzhiyun sp = XFS_SUMPTR(mp, bp, so);
496*4882a593Smuzhiyun if (delta) {
497*4882a593Smuzhiyun uint first = (uint)((char *)sp - (char *)bp->b_addr);
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun *sp += delta;
500*4882a593Smuzhiyun if (mp->m_rsum_cache) {
501*4882a593Smuzhiyun if (*sp == 0 && log == mp->m_rsum_cache[bbno])
502*4882a593Smuzhiyun mp->m_rsum_cache[bbno]++;
503*4882a593Smuzhiyun if (*sp != 0 && log < mp->m_rsum_cache[bbno])
504*4882a593Smuzhiyun mp->m_rsum_cache[bbno] = log;
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun xfs_trans_log_buf(tp, bp, first, first + sizeof(*sp) - 1);
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun if (sum)
509*4882a593Smuzhiyun *sum = *sp;
510*4882a593Smuzhiyun return 0;
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun int
xfs_rtmodify_summary(xfs_mount_t * mp,xfs_trans_t * tp,int log,xfs_rtblock_t bbno,int delta,xfs_buf_t ** rbpp,xfs_fsblock_t * rsb)514*4882a593Smuzhiyun xfs_rtmodify_summary(
515*4882a593Smuzhiyun xfs_mount_t *mp, /* file system mount structure */
516*4882a593Smuzhiyun xfs_trans_t *tp, /* transaction pointer */
517*4882a593Smuzhiyun int log, /* log2 of extent size */
518*4882a593Smuzhiyun xfs_rtblock_t bbno, /* bitmap block number */
519*4882a593Smuzhiyun int delta, /* change to make to summary info */
520*4882a593Smuzhiyun xfs_buf_t **rbpp, /* in/out: summary block buffer */
521*4882a593Smuzhiyun xfs_fsblock_t *rsb) /* in/out: summary block number */
522*4882a593Smuzhiyun {
523*4882a593Smuzhiyun return xfs_rtmodify_summary_int(mp, tp, log, bbno,
524*4882a593Smuzhiyun delta, rbpp, rsb, NULL);
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun /*
528*4882a593Smuzhiyun * Set the given range of bitmap bits to the given value.
529*4882a593Smuzhiyun * Do whatever I/O and logging is required.
530*4882a593Smuzhiyun */
531*4882a593Smuzhiyun int
xfs_rtmodify_range(xfs_mount_t * mp,xfs_trans_t * tp,xfs_rtblock_t start,xfs_extlen_t len,int val)532*4882a593Smuzhiyun xfs_rtmodify_range(
533*4882a593Smuzhiyun xfs_mount_t *mp, /* file system mount point */
534*4882a593Smuzhiyun xfs_trans_t *tp, /* transaction pointer */
535*4882a593Smuzhiyun xfs_rtblock_t start, /* starting block to modify */
536*4882a593Smuzhiyun xfs_extlen_t len, /* length of extent to modify */
537*4882a593Smuzhiyun int val) /* 1 for free, 0 for allocated */
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun xfs_rtword_t *b; /* current word in buffer */
540*4882a593Smuzhiyun int bit; /* bit number in the word */
541*4882a593Smuzhiyun xfs_rtblock_t block; /* bitmap block number */
542*4882a593Smuzhiyun xfs_buf_t *bp; /* buf for the block */
543*4882a593Smuzhiyun xfs_rtword_t *bufp; /* starting word in buffer */
544*4882a593Smuzhiyun int error; /* error value */
545*4882a593Smuzhiyun xfs_rtword_t *first; /* first used word in the buffer */
546*4882a593Smuzhiyun int i; /* current bit number rel. to start */
547*4882a593Smuzhiyun int lastbit; /* last useful bit in word */
548*4882a593Smuzhiyun xfs_rtword_t mask; /* mask o frelevant bits for value */
549*4882a593Smuzhiyun int word; /* word number in the buffer */
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun /*
552*4882a593Smuzhiyun * Compute starting bitmap block number.
553*4882a593Smuzhiyun */
554*4882a593Smuzhiyun block = XFS_BITTOBLOCK(mp, start);
555*4882a593Smuzhiyun /*
556*4882a593Smuzhiyun * Read the bitmap block, and point to its data.
557*4882a593Smuzhiyun */
558*4882a593Smuzhiyun error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
559*4882a593Smuzhiyun if (error) {
560*4882a593Smuzhiyun return error;
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun bufp = bp->b_addr;
563*4882a593Smuzhiyun /*
564*4882a593Smuzhiyun * Compute the starting word's address, and starting bit.
565*4882a593Smuzhiyun */
566*4882a593Smuzhiyun word = XFS_BITTOWORD(mp, start);
567*4882a593Smuzhiyun first = b = &bufp[word];
568*4882a593Smuzhiyun bit = (int)(start & (XFS_NBWORD - 1));
569*4882a593Smuzhiyun /*
570*4882a593Smuzhiyun * 0 (allocated) => all zeroes; 1 (free) => all ones.
571*4882a593Smuzhiyun */
572*4882a593Smuzhiyun val = -val;
573*4882a593Smuzhiyun /*
574*4882a593Smuzhiyun * If not starting on a word boundary, deal with the first
575*4882a593Smuzhiyun * (partial) word.
576*4882a593Smuzhiyun */
577*4882a593Smuzhiyun if (bit) {
578*4882a593Smuzhiyun /*
579*4882a593Smuzhiyun * Compute first bit not changed and mask of relevant bits.
580*4882a593Smuzhiyun */
581*4882a593Smuzhiyun lastbit = XFS_RTMIN(bit + len, XFS_NBWORD);
582*4882a593Smuzhiyun mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit;
583*4882a593Smuzhiyun /*
584*4882a593Smuzhiyun * Set/clear the active bits.
585*4882a593Smuzhiyun */
586*4882a593Smuzhiyun if (val)
587*4882a593Smuzhiyun *b |= mask;
588*4882a593Smuzhiyun else
589*4882a593Smuzhiyun *b &= ~mask;
590*4882a593Smuzhiyun i = lastbit - bit;
591*4882a593Smuzhiyun /*
592*4882a593Smuzhiyun * Go on to the next block if that's where the next word is
593*4882a593Smuzhiyun * and we need the next word.
594*4882a593Smuzhiyun */
595*4882a593Smuzhiyun if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
596*4882a593Smuzhiyun /*
597*4882a593Smuzhiyun * Log the changed part of this block.
598*4882a593Smuzhiyun * Get the next one.
599*4882a593Smuzhiyun */
600*4882a593Smuzhiyun xfs_trans_log_buf(tp, bp,
601*4882a593Smuzhiyun (uint)((char *)first - (char *)bufp),
602*4882a593Smuzhiyun (uint)((char *)b - (char *)bufp));
603*4882a593Smuzhiyun error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
604*4882a593Smuzhiyun if (error) {
605*4882a593Smuzhiyun return error;
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun first = b = bufp = bp->b_addr;
608*4882a593Smuzhiyun word = 0;
609*4882a593Smuzhiyun } else {
610*4882a593Smuzhiyun /*
611*4882a593Smuzhiyun * Go on to the next word in the buffer
612*4882a593Smuzhiyun */
613*4882a593Smuzhiyun b++;
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun } else {
616*4882a593Smuzhiyun /*
617*4882a593Smuzhiyun * Starting on a word boundary, no partial word.
618*4882a593Smuzhiyun */
619*4882a593Smuzhiyun i = 0;
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun /*
622*4882a593Smuzhiyun * Loop over whole words in buffers. When we use up one buffer
623*4882a593Smuzhiyun * we move on to the next one.
624*4882a593Smuzhiyun */
625*4882a593Smuzhiyun while (len - i >= XFS_NBWORD) {
626*4882a593Smuzhiyun /*
627*4882a593Smuzhiyun * Set the word value correctly.
628*4882a593Smuzhiyun */
629*4882a593Smuzhiyun *b = val;
630*4882a593Smuzhiyun i += XFS_NBWORD;
631*4882a593Smuzhiyun /*
632*4882a593Smuzhiyun * Go on to the next block if that's where the next word is
633*4882a593Smuzhiyun * and we need the next word.
634*4882a593Smuzhiyun */
635*4882a593Smuzhiyun if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
636*4882a593Smuzhiyun /*
637*4882a593Smuzhiyun * Log the changed part of this block.
638*4882a593Smuzhiyun * Get the next one.
639*4882a593Smuzhiyun */
640*4882a593Smuzhiyun xfs_trans_log_buf(tp, bp,
641*4882a593Smuzhiyun (uint)((char *)first - (char *)bufp),
642*4882a593Smuzhiyun (uint)((char *)b - (char *)bufp));
643*4882a593Smuzhiyun error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
644*4882a593Smuzhiyun if (error) {
645*4882a593Smuzhiyun return error;
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun first = b = bufp = bp->b_addr;
648*4882a593Smuzhiyun word = 0;
649*4882a593Smuzhiyun } else {
650*4882a593Smuzhiyun /*
651*4882a593Smuzhiyun * Go on to the next word in the buffer
652*4882a593Smuzhiyun */
653*4882a593Smuzhiyun b++;
654*4882a593Smuzhiyun }
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun /*
657*4882a593Smuzhiyun * If not ending on a word boundary, deal with the last
658*4882a593Smuzhiyun * (partial) word.
659*4882a593Smuzhiyun */
660*4882a593Smuzhiyun if ((lastbit = len - i)) {
661*4882a593Smuzhiyun /*
662*4882a593Smuzhiyun * Compute a mask of relevant bits.
663*4882a593Smuzhiyun */
664*4882a593Smuzhiyun mask = ((xfs_rtword_t)1 << lastbit) - 1;
665*4882a593Smuzhiyun /*
666*4882a593Smuzhiyun * Set/clear the active bits.
667*4882a593Smuzhiyun */
668*4882a593Smuzhiyun if (val)
669*4882a593Smuzhiyun *b |= mask;
670*4882a593Smuzhiyun else
671*4882a593Smuzhiyun *b &= ~mask;
672*4882a593Smuzhiyun b++;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun /*
675*4882a593Smuzhiyun * Log any remaining changed bytes.
676*4882a593Smuzhiyun */
677*4882a593Smuzhiyun if (b > first)
678*4882a593Smuzhiyun xfs_trans_log_buf(tp, bp, (uint)((char *)first - (char *)bufp),
679*4882a593Smuzhiyun (uint)((char *)b - (char *)bufp - 1));
680*4882a593Smuzhiyun return 0;
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun /*
684*4882a593Smuzhiyun * Mark an extent specified by start and len freed.
685*4882a593Smuzhiyun * Updates all the summary information as well as the bitmap.
686*4882a593Smuzhiyun */
687*4882a593Smuzhiyun int
xfs_rtfree_range(xfs_mount_t * mp,xfs_trans_t * tp,xfs_rtblock_t start,xfs_extlen_t len,xfs_buf_t ** rbpp,xfs_fsblock_t * rsb)688*4882a593Smuzhiyun xfs_rtfree_range(
689*4882a593Smuzhiyun xfs_mount_t *mp, /* file system mount point */
690*4882a593Smuzhiyun xfs_trans_t *tp, /* transaction pointer */
691*4882a593Smuzhiyun xfs_rtblock_t start, /* starting block to free */
692*4882a593Smuzhiyun xfs_extlen_t len, /* length to free */
693*4882a593Smuzhiyun xfs_buf_t **rbpp, /* in/out: summary block buffer */
694*4882a593Smuzhiyun xfs_fsblock_t *rsb) /* in/out: summary block number */
695*4882a593Smuzhiyun {
696*4882a593Smuzhiyun xfs_rtblock_t end; /* end of the freed extent */
697*4882a593Smuzhiyun int error; /* error value */
698*4882a593Smuzhiyun xfs_rtblock_t postblock; /* first block freed > end */
699*4882a593Smuzhiyun xfs_rtblock_t preblock; /* first block freed < start */
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun end = start + len - 1;
702*4882a593Smuzhiyun /*
703*4882a593Smuzhiyun * Modify the bitmap to mark this extent freed.
704*4882a593Smuzhiyun */
705*4882a593Smuzhiyun error = xfs_rtmodify_range(mp, tp, start, len, 1);
706*4882a593Smuzhiyun if (error) {
707*4882a593Smuzhiyun return error;
708*4882a593Smuzhiyun }
709*4882a593Smuzhiyun /*
710*4882a593Smuzhiyun * Assume we're freeing out of the middle of an allocated extent.
711*4882a593Smuzhiyun * We need to find the beginning and end of the extent so we can
712*4882a593Smuzhiyun * properly update the summary.
713*4882a593Smuzhiyun */
714*4882a593Smuzhiyun error = xfs_rtfind_back(mp, tp, start, 0, &preblock);
715*4882a593Smuzhiyun if (error) {
716*4882a593Smuzhiyun return error;
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun /*
719*4882a593Smuzhiyun * Find the next allocated block (end of allocated extent).
720*4882a593Smuzhiyun */
721*4882a593Smuzhiyun error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1,
722*4882a593Smuzhiyun &postblock);
723*4882a593Smuzhiyun if (error)
724*4882a593Smuzhiyun return error;
725*4882a593Smuzhiyun /*
726*4882a593Smuzhiyun * If there are blocks not being freed at the front of the
727*4882a593Smuzhiyun * old extent, add summary data for them to be allocated.
728*4882a593Smuzhiyun */
729*4882a593Smuzhiyun if (preblock < start) {
730*4882a593Smuzhiyun error = xfs_rtmodify_summary(mp, tp,
731*4882a593Smuzhiyun XFS_RTBLOCKLOG(start - preblock),
732*4882a593Smuzhiyun XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb);
733*4882a593Smuzhiyun if (error) {
734*4882a593Smuzhiyun return error;
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun }
737*4882a593Smuzhiyun /*
738*4882a593Smuzhiyun * If there are blocks not being freed at the end of the
739*4882a593Smuzhiyun * old extent, add summary data for them to be allocated.
740*4882a593Smuzhiyun */
741*4882a593Smuzhiyun if (postblock > end) {
742*4882a593Smuzhiyun error = xfs_rtmodify_summary(mp, tp,
743*4882a593Smuzhiyun XFS_RTBLOCKLOG(postblock - end),
744*4882a593Smuzhiyun XFS_BITTOBLOCK(mp, end + 1), -1, rbpp, rsb);
745*4882a593Smuzhiyun if (error) {
746*4882a593Smuzhiyun return error;
747*4882a593Smuzhiyun }
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun /*
750*4882a593Smuzhiyun * Increment the summary information corresponding to the entire
751*4882a593Smuzhiyun * (new) free extent.
752*4882a593Smuzhiyun */
753*4882a593Smuzhiyun error = xfs_rtmodify_summary(mp, tp,
754*4882a593Smuzhiyun XFS_RTBLOCKLOG(postblock + 1 - preblock),
755*4882a593Smuzhiyun XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb);
756*4882a593Smuzhiyun return error;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun /*
760*4882a593Smuzhiyun * Check that the given range is either all allocated (val = 0) or
761*4882a593Smuzhiyun * all free (val = 1).
762*4882a593Smuzhiyun */
763*4882a593Smuzhiyun int
xfs_rtcheck_range(xfs_mount_t * mp,xfs_trans_t * tp,xfs_rtblock_t start,xfs_extlen_t len,int val,xfs_rtblock_t * new,int * stat)764*4882a593Smuzhiyun xfs_rtcheck_range(
765*4882a593Smuzhiyun xfs_mount_t *mp, /* file system mount point */
766*4882a593Smuzhiyun xfs_trans_t *tp, /* transaction pointer */
767*4882a593Smuzhiyun xfs_rtblock_t start, /* starting block number of extent */
768*4882a593Smuzhiyun xfs_extlen_t len, /* length of extent */
769*4882a593Smuzhiyun int val, /* 1 for free, 0 for allocated */
770*4882a593Smuzhiyun xfs_rtblock_t *new, /* out: first block not matching */
771*4882a593Smuzhiyun int *stat) /* out: 1 for matches, 0 for not */
772*4882a593Smuzhiyun {
773*4882a593Smuzhiyun xfs_rtword_t *b; /* current word in buffer */
774*4882a593Smuzhiyun int bit; /* bit number in the word */
775*4882a593Smuzhiyun xfs_rtblock_t block; /* bitmap block number */
776*4882a593Smuzhiyun xfs_buf_t *bp; /* buf for the block */
777*4882a593Smuzhiyun xfs_rtword_t *bufp; /* starting word in buffer */
778*4882a593Smuzhiyun int error; /* error value */
779*4882a593Smuzhiyun xfs_rtblock_t i; /* current bit number rel. to start */
780*4882a593Smuzhiyun xfs_rtblock_t lastbit; /* last useful bit in word */
781*4882a593Smuzhiyun xfs_rtword_t mask; /* mask of relevant bits for value */
782*4882a593Smuzhiyun xfs_rtword_t wdiff; /* difference from wanted value */
783*4882a593Smuzhiyun int word; /* word number in the buffer */
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun /*
786*4882a593Smuzhiyun * Compute starting bitmap block number
787*4882a593Smuzhiyun */
788*4882a593Smuzhiyun block = XFS_BITTOBLOCK(mp, start);
789*4882a593Smuzhiyun /*
790*4882a593Smuzhiyun * Read the bitmap block.
791*4882a593Smuzhiyun */
792*4882a593Smuzhiyun error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
793*4882a593Smuzhiyun if (error) {
794*4882a593Smuzhiyun return error;
795*4882a593Smuzhiyun }
796*4882a593Smuzhiyun bufp = bp->b_addr;
797*4882a593Smuzhiyun /*
798*4882a593Smuzhiyun * Compute the starting word's address, and starting bit.
799*4882a593Smuzhiyun */
800*4882a593Smuzhiyun word = XFS_BITTOWORD(mp, start);
801*4882a593Smuzhiyun b = &bufp[word];
802*4882a593Smuzhiyun bit = (int)(start & (XFS_NBWORD - 1));
803*4882a593Smuzhiyun /*
804*4882a593Smuzhiyun * 0 (allocated) => all zero's; 1 (free) => all one's.
805*4882a593Smuzhiyun */
806*4882a593Smuzhiyun val = -val;
807*4882a593Smuzhiyun /*
808*4882a593Smuzhiyun * If not starting on a word boundary, deal with the first
809*4882a593Smuzhiyun * (partial) word.
810*4882a593Smuzhiyun */
811*4882a593Smuzhiyun if (bit) {
812*4882a593Smuzhiyun /*
813*4882a593Smuzhiyun * Compute first bit not examined.
814*4882a593Smuzhiyun */
815*4882a593Smuzhiyun lastbit = XFS_RTMIN(bit + len, XFS_NBWORD);
816*4882a593Smuzhiyun /*
817*4882a593Smuzhiyun * Mask of relevant bits.
818*4882a593Smuzhiyun */
819*4882a593Smuzhiyun mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit;
820*4882a593Smuzhiyun /*
821*4882a593Smuzhiyun * Compute difference between actual and desired value.
822*4882a593Smuzhiyun */
823*4882a593Smuzhiyun if ((wdiff = (*b ^ val) & mask)) {
824*4882a593Smuzhiyun /*
825*4882a593Smuzhiyun * Different, compute first wrong bit and return.
826*4882a593Smuzhiyun */
827*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
828*4882a593Smuzhiyun i = XFS_RTLOBIT(wdiff) - bit;
829*4882a593Smuzhiyun *new = start + i;
830*4882a593Smuzhiyun *stat = 0;
831*4882a593Smuzhiyun return 0;
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun i = lastbit - bit;
834*4882a593Smuzhiyun /*
835*4882a593Smuzhiyun * Go on to next block if that's where the next word is
836*4882a593Smuzhiyun * and we need the next word.
837*4882a593Smuzhiyun */
838*4882a593Smuzhiyun if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
839*4882a593Smuzhiyun /*
840*4882a593Smuzhiyun * If done with this block, get the next one.
841*4882a593Smuzhiyun */
842*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
843*4882a593Smuzhiyun error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
844*4882a593Smuzhiyun if (error) {
845*4882a593Smuzhiyun return error;
846*4882a593Smuzhiyun }
847*4882a593Smuzhiyun b = bufp = bp->b_addr;
848*4882a593Smuzhiyun word = 0;
849*4882a593Smuzhiyun } else {
850*4882a593Smuzhiyun /*
851*4882a593Smuzhiyun * Go on to the next word in the buffer.
852*4882a593Smuzhiyun */
853*4882a593Smuzhiyun b++;
854*4882a593Smuzhiyun }
855*4882a593Smuzhiyun } else {
856*4882a593Smuzhiyun /*
857*4882a593Smuzhiyun * Starting on a word boundary, no partial word.
858*4882a593Smuzhiyun */
859*4882a593Smuzhiyun i = 0;
860*4882a593Smuzhiyun }
861*4882a593Smuzhiyun /*
862*4882a593Smuzhiyun * Loop over whole words in buffers. When we use up one buffer
863*4882a593Smuzhiyun * we move on to the next one.
864*4882a593Smuzhiyun */
865*4882a593Smuzhiyun while (len - i >= XFS_NBWORD) {
866*4882a593Smuzhiyun /*
867*4882a593Smuzhiyun * Compute difference between actual and desired value.
868*4882a593Smuzhiyun */
869*4882a593Smuzhiyun if ((wdiff = *b ^ val)) {
870*4882a593Smuzhiyun /*
871*4882a593Smuzhiyun * Different, compute first wrong bit and return.
872*4882a593Smuzhiyun */
873*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
874*4882a593Smuzhiyun i += XFS_RTLOBIT(wdiff);
875*4882a593Smuzhiyun *new = start + i;
876*4882a593Smuzhiyun *stat = 0;
877*4882a593Smuzhiyun return 0;
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun i += XFS_NBWORD;
880*4882a593Smuzhiyun /*
881*4882a593Smuzhiyun * Go on to next block if that's where the next word is
882*4882a593Smuzhiyun * and we need the next word.
883*4882a593Smuzhiyun */
884*4882a593Smuzhiyun if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
885*4882a593Smuzhiyun /*
886*4882a593Smuzhiyun * If done with this block, get the next one.
887*4882a593Smuzhiyun */
888*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
889*4882a593Smuzhiyun error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
890*4882a593Smuzhiyun if (error) {
891*4882a593Smuzhiyun return error;
892*4882a593Smuzhiyun }
893*4882a593Smuzhiyun b = bufp = bp->b_addr;
894*4882a593Smuzhiyun word = 0;
895*4882a593Smuzhiyun } else {
896*4882a593Smuzhiyun /*
897*4882a593Smuzhiyun * Go on to the next word in the buffer.
898*4882a593Smuzhiyun */
899*4882a593Smuzhiyun b++;
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun /*
903*4882a593Smuzhiyun * If not ending on a word boundary, deal with the last
904*4882a593Smuzhiyun * (partial) word.
905*4882a593Smuzhiyun */
906*4882a593Smuzhiyun if ((lastbit = len - i)) {
907*4882a593Smuzhiyun /*
908*4882a593Smuzhiyun * Mask of relevant bits.
909*4882a593Smuzhiyun */
910*4882a593Smuzhiyun mask = ((xfs_rtword_t)1 << lastbit) - 1;
911*4882a593Smuzhiyun /*
912*4882a593Smuzhiyun * Compute difference between actual and desired value.
913*4882a593Smuzhiyun */
914*4882a593Smuzhiyun if ((wdiff = (*b ^ val) & mask)) {
915*4882a593Smuzhiyun /*
916*4882a593Smuzhiyun * Different, compute first wrong bit and return.
917*4882a593Smuzhiyun */
918*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
919*4882a593Smuzhiyun i += XFS_RTLOBIT(wdiff);
920*4882a593Smuzhiyun *new = start + i;
921*4882a593Smuzhiyun *stat = 0;
922*4882a593Smuzhiyun return 0;
923*4882a593Smuzhiyun } else
924*4882a593Smuzhiyun i = len;
925*4882a593Smuzhiyun }
926*4882a593Smuzhiyun /*
927*4882a593Smuzhiyun * Successful, return.
928*4882a593Smuzhiyun */
929*4882a593Smuzhiyun xfs_trans_brelse(tp, bp);
930*4882a593Smuzhiyun *new = start + i;
931*4882a593Smuzhiyun *stat = 1;
932*4882a593Smuzhiyun return 0;
933*4882a593Smuzhiyun }
934*4882a593Smuzhiyun
935*4882a593Smuzhiyun #ifdef DEBUG
936*4882a593Smuzhiyun /*
937*4882a593Smuzhiyun * Check that the given extent (block range) is allocated already.
938*4882a593Smuzhiyun */
939*4882a593Smuzhiyun STATIC int /* error */
xfs_rtcheck_alloc_range(xfs_mount_t * mp,xfs_trans_t * tp,xfs_rtblock_t bno,xfs_extlen_t len)940*4882a593Smuzhiyun xfs_rtcheck_alloc_range(
941*4882a593Smuzhiyun xfs_mount_t *mp, /* file system mount point */
942*4882a593Smuzhiyun xfs_trans_t *tp, /* transaction pointer */
943*4882a593Smuzhiyun xfs_rtblock_t bno, /* starting block number of extent */
944*4882a593Smuzhiyun xfs_extlen_t len) /* length of extent */
945*4882a593Smuzhiyun {
946*4882a593Smuzhiyun xfs_rtblock_t new; /* dummy for xfs_rtcheck_range */
947*4882a593Smuzhiyun int stat;
948*4882a593Smuzhiyun int error;
949*4882a593Smuzhiyun
950*4882a593Smuzhiyun error = xfs_rtcheck_range(mp, tp, bno, len, 0, &new, &stat);
951*4882a593Smuzhiyun if (error)
952*4882a593Smuzhiyun return error;
953*4882a593Smuzhiyun ASSERT(stat);
954*4882a593Smuzhiyun return 0;
955*4882a593Smuzhiyun }
956*4882a593Smuzhiyun #else
957*4882a593Smuzhiyun #define xfs_rtcheck_alloc_range(m,t,b,l) (0)
958*4882a593Smuzhiyun #endif
959*4882a593Smuzhiyun /*
960*4882a593Smuzhiyun * Free an extent in the realtime subvolume. Length is expressed in
961*4882a593Smuzhiyun * realtime extents, as is the block number.
962*4882a593Smuzhiyun */
963*4882a593Smuzhiyun int /* error */
xfs_rtfree_extent(xfs_trans_t * tp,xfs_rtblock_t bno,xfs_extlen_t len)964*4882a593Smuzhiyun xfs_rtfree_extent(
965*4882a593Smuzhiyun xfs_trans_t *tp, /* transaction pointer */
966*4882a593Smuzhiyun xfs_rtblock_t bno, /* starting block number to free */
967*4882a593Smuzhiyun xfs_extlen_t len) /* length of extent freed */
968*4882a593Smuzhiyun {
969*4882a593Smuzhiyun int error; /* error value */
970*4882a593Smuzhiyun xfs_mount_t *mp; /* file system mount structure */
971*4882a593Smuzhiyun xfs_fsblock_t sb; /* summary file block number */
972*4882a593Smuzhiyun xfs_buf_t *sumbp = NULL; /* summary file block buffer */
973*4882a593Smuzhiyun
974*4882a593Smuzhiyun mp = tp->t_mountp;
975*4882a593Smuzhiyun
976*4882a593Smuzhiyun ASSERT(mp->m_rbmip->i_itemp != NULL);
977*4882a593Smuzhiyun ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun error = xfs_rtcheck_alloc_range(mp, tp, bno, len);
980*4882a593Smuzhiyun if (error)
981*4882a593Smuzhiyun return error;
982*4882a593Smuzhiyun
983*4882a593Smuzhiyun /*
984*4882a593Smuzhiyun * Free the range of realtime blocks.
985*4882a593Smuzhiyun */
986*4882a593Smuzhiyun error = xfs_rtfree_range(mp, tp, bno, len, &sumbp, &sb);
987*4882a593Smuzhiyun if (error) {
988*4882a593Smuzhiyun return error;
989*4882a593Smuzhiyun }
990*4882a593Smuzhiyun /*
991*4882a593Smuzhiyun * Mark more blocks free in the superblock.
992*4882a593Smuzhiyun */
993*4882a593Smuzhiyun xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, (long)len);
994*4882a593Smuzhiyun /*
995*4882a593Smuzhiyun * If we've now freed all the blocks, reset the file sequence
996*4882a593Smuzhiyun * number to 0.
997*4882a593Smuzhiyun */
998*4882a593Smuzhiyun if (tp->t_frextents_delta + mp->m_sb.sb_frextents ==
999*4882a593Smuzhiyun mp->m_sb.sb_rextents) {
1000*4882a593Smuzhiyun if (!(mp->m_rbmip->i_d.di_flags & XFS_DIFLAG_NEWRTBM))
1001*4882a593Smuzhiyun mp->m_rbmip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM;
1002*4882a593Smuzhiyun *(uint64_t *)&VFS_I(mp->m_rbmip)->i_atime = 0;
1003*4882a593Smuzhiyun xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun return 0;
1006*4882a593Smuzhiyun }
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun /* Find all the free records within a given range. */
1009*4882a593Smuzhiyun int
xfs_rtalloc_query_range(struct xfs_trans * tp,struct xfs_rtalloc_rec * low_rec,struct xfs_rtalloc_rec * high_rec,xfs_rtalloc_query_range_fn fn,void * priv)1010*4882a593Smuzhiyun xfs_rtalloc_query_range(
1011*4882a593Smuzhiyun struct xfs_trans *tp,
1012*4882a593Smuzhiyun struct xfs_rtalloc_rec *low_rec,
1013*4882a593Smuzhiyun struct xfs_rtalloc_rec *high_rec,
1014*4882a593Smuzhiyun xfs_rtalloc_query_range_fn fn,
1015*4882a593Smuzhiyun void *priv)
1016*4882a593Smuzhiyun {
1017*4882a593Smuzhiyun struct xfs_rtalloc_rec rec;
1018*4882a593Smuzhiyun struct xfs_mount *mp = tp->t_mountp;
1019*4882a593Smuzhiyun xfs_rtblock_t rtstart;
1020*4882a593Smuzhiyun xfs_rtblock_t rtend;
1021*4882a593Smuzhiyun int is_free;
1022*4882a593Smuzhiyun int error = 0;
1023*4882a593Smuzhiyun
1024*4882a593Smuzhiyun if (low_rec->ar_startext > high_rec->ar_startext)
1025*4882a593Smuzhiyun return -EINVAL;
1026*4882a593Smuzhiyun if (low_rec->ar_startext >= mp->m_sb.sb_rextents ||
1027*4882a593Smuzhiyun low_rec->ar_startext == high_rec->ar_startext)
1028*4882a593Smuzhiyun return 0;
1029*4882a593Smuzhiyun high_rec->ar_startext = min(high_rec->ar_startext,
1030*4882a593Smuzhiyun mp->m_sb.sb_rextents - 1);
1031*4882a593Smuzhiyun
1032*4882a593Smuzhiyun /* Iterate the bitmap, looking for discrepancies. */
1033*4882a593Smuzhiyun rtstart = low_rec->ar_startext;
1034*4882a593Smuzhiyun while (rtstart <= high_rec->ar_startext) {
1035*4882a593Smuzhiyun /* Is the first block free? */
1036*4882a593Smuzhiyun error = xfs_rtcheck_range(mp, tp, rtstart, 1, 1, &rtend,
1037*4882a593Smuzhiyun &is_free);
1038*4882a593Smuzhiyun if (error)
1039*4882a593Smuzhiyun break;
1040*4882a593Smuzhiyun
1041*4882a593Smuzhiyun /* How long does the extent go for? */
1042*4882a593Smuzhiyun error = xfs_rtfind_forw(mp, tp, rtstart,
1043*4882a593Smuzhiyun high_rec->ar_startext, &rtend);
1044*4882a593Smuzhiyun if (error)
1045*4882a593Smuzhiyun break;
1046*4882a593Smuzhiyun
1047*4882a593Smuzhiyun if (is_free) {
1048*4882a593Smuzhiyun rec.ar_startext = rtstart;
1049*4882a593Smuzhiyun rec.ar_extcount = rtend - rtstart + 1;
1050*4882a593Smuzhiyun
1051*4882a593Smuzhiyun error = fn(tp, &rec, priv);
1052*4882a593Smuzhiyun if (error)
1053*4882a593Smuzhiyun break;
1054*4882a593Smuzhiyun }
1055*4882a593Smuzhiyun
1056*4882a593Smuzhiyun rtstart = rtend + 1;
1057*4882a593Smuzhiyun }
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun return error;
1060*4882a593Smuzhiyun }
1061*4882a593Smuzhiyun
1062*4882a593Smuzhiyun /* Find all the free records. */
1063*4882a593Smuzhiyun int
xfs_rtalloc_query_all(struct xfs_trans * tp,xfs_rtalloc_query_range_fn fn,void * priv)1064*4882a593Smuzhiyun xfs_rtalloc_query_all(
1065*4882a593Smuzhiyun struct xfs_trans *tp,
1066*4882a593Smuzhiyun xfs_rtalloc_query_range_fn fn,
1067*4882a593Smuzhiyun void *priv)
1068*4882a593Smuzhiyun {
1069*4882a593Smuzhiyun struct xfs_rtalloc_rec keys[2];
1070*4882a593Smuzhiyun
1071*4882a593Smuzhiyun keys[0].ar_startext = 0;
1072*4882a593Smuzhiyun keys[1].ar_startext = tp->t_mountp->m_sb.sb_rextents - 1;
1073*4882a593Smuzhiyun keys[0].ar_extcount = keys[1].ar_extcount = 0;
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun return xfs_rtalloc_query_range(tp, &keys[0], &keys[1], fn, priv);
1076*4882a593Smuzhiyun }
1077*4882a593Smuzhiyun
1078*4882a593Smuzhiyun /* Is the given extent all free? */
1079*4882a593Smuzhiyun int
xfs_rtalloc_extent_is_free(struct xfs_mount * mp,struct xfs_trans * tp,xfs_rtblock_t start,xfs_extlen_t len,bool * is_free)1080*4882a593Smuzhiyun xfs_rtalloc_extent_is_free(
1081*4882a593Smuzhiyun struct xfs_mount *mp,
1082*4882a593Smuzhiyun struct xfs_trans *tp,
1083*4882a593Smuzhiyun xfs_rtblock_t start,
1084*4882a593Smuzhiyun xfs_extlen_t len,
1085*4882a593Smuzhiyun bool *is_free)
1086*4882a593Smuzhiyun {
1087*4882a593Smuzhiyun xfs_rtblock_t end;
1088*4882a593Smuzhiyun int matches;
1089*4882a593Smuzhiyun int error;
1090*4882a593Smuzhiyun
1091*4882a593Smuzhiyun error = xfs_rtcheck_range(mp, tp, start, len, 1, &end, &matches);
1092*4882a593Smuzhiyun if (error)
1093*4882a593Smuzhiyun return error;
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun *is_free = matches;
1096*4882a593Smuzhiyun return 0;
1097*4882a593Smuzhiyun }
1098