162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2000-2005 Silicon Graphics, Inc. 462306a36Sopenharmony_ci * All Rights Reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include "xfs.h" 762306a36Sopenharmony_ci#include "xfs_fs.h" 862306a36Sopenharmony_ci#include "xfs_shared.h" 962306a36Sopenharmony_ci#include "xfs_format.h" 1062306a36Sopenharmony_ci#include "xfs_log_format.h" 1162306a36Sopenharmony_ci#include "xfs_trans_resv.h" 1262306a36Sopenharmony_ci#include "xfs_bit.h" 1362306a36Sopenharmony_ci#include "xfs_mount.h" 1462306a36Sopenharmony_ci#include "xfs_inode.h" 1562306a36Sopenharmony_ci#include "xfs_bmap.h" 1662306a36Sopenharmony_ci#include "xfs_trans.h" 1762306a36Sopenharmony_ci#include "xfs_rtalloc.h" 1862306a36Sopenharmony_ci#include "xfs_error.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* 2162306a36Sopenharmony_ci * Realtime allocator bitmap functions shared with userspace. 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * Real time buffers need verifiers to avoid runtime warnings during IO. 2662306a36Sopenharmony_ci * We don't have anything to verify, however, so these are just dummy 2762306a36Sopenharmony_ci * operations. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_cistatic void 3062306a36Sopenharmony_cixfs_rtbuf_verify_read( 3162306a36Sopenharmony_ci struct xfs_buf *bp) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci return; 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic void 3762306a36Sopenharmony_cixfs_rtbuf_verify_write( 3862306a36Sopenharmony_ci struct xfs_buf *bp) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci return; 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ciconst struct xfs_buf_ops xfs_rtbuf_ops = { 4462306a36Sopenharmony_ci .name = "rtbuf", 4562306a36Sopenharmony_ci .verify_read = xfs_rtbuf_verify_read, 4662306a36Sopenharmony_ci .verify_write = xfs_rtbuf_verify_write, 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* 5062306a36Sopenharmony_ci * Get a buffer for the bitmap or summary file block specified. 5162306a36Sopenharmony_ci * The buffer is returned read and locked. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ciint 5462306a36Sopenharmony_cixfs_rtbuf_get( 5562306a36Sopenharmony_ci xfs_mount_t *mp, /* file system mount structure */ 5662306a36Sopenharmony_ci xfs_trans_t *tp, /* transaction pointer */ 5762306a36Sopenharmony_ci xfs_rtblock_t block, /* block number in bitmap or summary */ 5862306a36Sopenharmony_ci int issum, /* is summary not bitmap */ 5962306a36Sopenharmony_ci struct xfs_buf **bpp) /* output: buffer for the block */ 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct xfs_buf *bp; /* block buffer, result */ 6262306a36Sopenharmony_ci xfs_inode_t *ip; /* bitmap or summary inode */ 6362306a36Sopenharmony_ci xfs_bmbt_irec_t map; 6462306a36Sopenharmony_ci int nmap = 1; 6562306a36Sopenharmony_ci int error; /* error value */ 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci ip = issum ? mp->m_rsumip : mp->m_rbmip; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci error = xfs_bmapi_read(ip, block, 1, &map, &nmap, 0); 7062306a36Sopenharmony_ci if (error) 7162306a36Sopenharmony_ci return error; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (XFS_IS_CORRUPT(mp, nmap == 0 || !xfs_bmap_is_written_extent(&map))) 7462306a36Sopenharmony_ci return -EFSCORRUPTED; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci ASSERT(map.br_startblock != NULLFSBLOCK); 7762306a36Sopenharmony_ci error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, 7862306a36Sopenharmony_ci XFS_FSB_TO_DADDR(mp, map.br_startblock), 7962306a36Sopenharmony_ci mp->m_bsize, 0, &bp, &xfs_rtbuf_ops); 8062306a36Sopenharmony_ci if (error) 8162306a36Sopenharmony_ci return error; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci xfs_trans_buf_set_type(tp, bp, issum ? XFS_BLFT_RTSUMMARY_BUF 8462306a36Sopenharmony_ci : XFS_BLFT_RTBITMAP_BUF); 8562306a36Sopenharmony_ci *bpp = bp; 8662306a36Sopenharmony_ci return 0; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* 9062306a36Sopenharmony_ci * Searching backward from start to limit, find the first block whose 9162306a36Sopenharmony_ci * allocated/free state is different from start's. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_ciint 9462306a36Sopenharmony_cixfs_rtfind_back( 9562306a36Sopenharmony_ci xfs_mount_t *mp, /* file system mount point */ 9662306a36Sopenharmony_ci xfs_trans_t *tp, /* transaction pointer */ 9762306a36Sopenharmony_ci xfs_rtblock_t start, /* starting block to look at */ 9862306a36Sopenharmony_ci xfs_rtblock_t limit, /* last block to look at */ 9962306a36Sopenharmony_ci xfs_rtblock_t *rtblock) /* out: start block found */ 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci xfs_rtword_t *b; /* current word in buffer */ 10262306a36Sopenharmony_ci int bit; /* bit number in the word */ 10362306a36Sopenharmony_ci xfs_rtblock_t block; /* bitmap block number */ 10462306a36Sopenharmony_ci struct xfs_buf *bp; /* buf for the block */ 10562306a36Sopenharmony_ci xfs_rtword_t *bufp; /* starting word in buffer */ 10662306a36Sopenharmony_ci int error; /* error value */ 10762306a36Sopenharmony_ci xfs_rtblock_t firstbit; /* first useful bit in the word */ 10862306a36Sopenharmony_ci xfs_rtblock_t i; /* current bit number rel. to start */ 10962306a36Sopenharmony_ci xfs_rtblock_t len; /* length of inspected area */ 11062306a36Sopenharmony_ci xfs_rtword_t mask; /* mask of relevant bits for value */ 11162306a36Sopenharmony_ci xfs_rtword_t want; /* mask for "good" values */ 11262306a36Sopenharmony_ci xfs_rtword_t wdiff; /* difference from wanted value */ 11362306a36Sopenharmony_ci int word; /* word number in the buffer */ 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* 11662306a36Sopenharmony_ci * Compute and read in starting bitmap block for starting block. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci block = XFS_BITTOBLOCK(mp, start); 11962306a36Sopenharmony_ci error = xfs_rtbuf_get(mp, tp, block, 0, &bp); 12062306a36Sopenharmony_ci if (error) { 12162306a36Sopenharmony_ci return error; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci bufp = bp->b_addr; 12462306a36Sopenharmony_ci /* 12562306a36Sopenharmony_ci * Get the first word's index & point to it. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_ci word = XFS_BITTOWORD(mp, start); 12862306a36Sopenharmony_ci b = &bufp[word]; 12962306a36Sopenharmony_ci bit = (int)(start & (XFS_NBWORD - 1)); 13062306a36Sopenharmony_ci len = start - limit + 1; 13162306a36Sopenharmony_ci /* 13262306a36Sopenharmony_ci * Compute match value, based on the bit at start: if 1 (free) 13362306a36Sopenharmony_ci * then all-ones, else all-zeroes. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0; 13662306a36Sopenharmony_ci /* 13762306a36Sopenharmony_ci * If the starting position is not word-aligned, deal with the 13862306a36Sopenharmony_ci * partial word. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci if (bit < XFS_NBWORD - 1) { 14162306a36Sopenharmony_ci /* 14262306a36Sopenharmony_ci * Calculate first (leftmost) bit number to look at, 14362306a36Sopenharmony_ci * and mask for all the relevant bits in this word. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci firstbit = XFS_RTMAX((xfs_srtblock_t)(bit - len + 1), 0); 14662306a36Sopenharmony_ci mask = (((xfs_rtword_t)1 << (bit - firstbit + 1)) - 1) << 14762306a36Sopenharmony_ci firstbit; 14862306a36Sopenharmony_ci /* 14962306a36Sopenharmony_ci * Calculate the difference between the value there 15062306a36Sopenharmony_ci * and what we're looking for. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_ci if ((wdiff = (*b ^ want) & mask)) { 15362306a36Sopenharmony_ci /* 15462306a36Sopenharmony_ci * Different. Mark where we are and return. 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 15762306a36Sopenharmony_ci i = bit - XFS_RTHIBIT(wdiff); 15862306a36Sopenharmony_ci *rtblock = start - i + 1; 15962306a36Sopenharmony_ci return 0; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci i = bit - firstbit + 1; 16262306a36Sopenharmony_ci /* 16362306a36Sopenharmony_ci * Go on to previous block if that's where the previous word is 16462306a36Sopenharmony_ci * and we need the previous word. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_ci if (--word == -1 && i < len) { 16762306a36Sopenharmony_ci /* 16862306a36Sopenharmony_ci * If done with this block, get the previous one. 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 17162306a36Sopenharmony_ci error = xfs_rtbuf_get(mp, tp, --block, 0, &bp); 17262306a36Sopenharmony_ci if (error) { 17362306a36Sopenharmony_ci return error; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci bufp = bp->b_addr; 17662306a36Sopenharmony_ci word = XFS_BLOCKWMASK(mp); 17762306a36Sopenharmony_ci b = &bufp[word]; 17862306a36Sopenharmony_ci } else { 17962306a36Sopenharmony_ci /* 18062306a36Sopenharmony_ci * Go on to the previous word in the buffer. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci b--; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci } else { 18562306a36Sopenharmony_ci /* 18662306a36Sopenharmony_ci * Starting on a word boundary, no partial word. 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_ci i = 0; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci /* 19162306a36Sopenharmony_ci * Loop over whole words in buffers. When we use up one buffer 19262306a36Sopenharmony_ci * we move on to the previous one. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci while (len - i >= XFS_NBWORD) { 19562306a36Sopenharmony_ci /* 19662306a36Sopenharmony_ci * Compute difference between actual and desired value. 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci if ((wdiff = *b ^ want)) { 19962306a36Sopenharmony_ci /* 20062306a36Sopenharmony_ci * Different, mark where we are and return. 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 20362306a36Sopenharmony_ci i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff); 20462306a36Sopenharmony_ci *rtblock = start - i + 1; 20562306a36Sopenharmony_ci return 0; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci i += XFS_NBWORD; 20862306a36Sopenharmony_ci /* 20962306a36Sopenharmony_ci * Go on to previous block if that's where the previous word is 21062306a36Sopenharmony_ci * and we need the previous word. 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_ci if (--word == -1 && i < len) { 21362306a36Sopenharmony_ci /* 21462306a36Sopenharmony_ci * If done with this block, get the previous one. 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 21762306a36Sopenharmony_ci error = xfs_rtbuf_get(mp, tp, --block, 0, &bp); 21862306a36Sopenharmony_ci if (error) { 21962306a36Sopenharmony_ci return error; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci bufp = bp->b_addr; 22262306a36Sopenharmony_ci word = XFS_BLOCKWMASK(mp); 22362306a36Sopenharmony_ci b = &bufp[word]; 22462306a36Sopenharmony_ci } else { 22562306a36Sopenharmony_ci /* 22662306a36Sopenharmony_ci * Go on to the previous word in the buffer. 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_ci b--; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci /* 23262306a36Sopenharmony_ci * If not ending on a word boundary, deal with the last 23362306a36Sopenharmony_ci * (partial) word. 23462306a36Sopenharmony_ci */ 23562306a36Sopenharmony_ci if (len - i) { 23662306a36Sopenharmony_ci /* 23762306a36Sopenharmony_ci * Calculate first (leftmost) bit number to look at, 23862306a36Sopenharmony_ci * and mask for all the relevant bits in this word. 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_ci firstbit = XFS_NBWORD - (len - i); 24162306a36Sopenharmony_ci mask = (((xfs_rtword_t)1 << (len - i)) - 1) << firstbit; 24262306a36Sopenharmony_ci /* 24362306a36Sopenharmony_ci * Compute difference between actual and desired value. 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_ci if ((wdiff = (*b ^ want) & mask)) { 24662306a36Sopenharmony_ci /* 24762306a36Sopenharmony_ci * Different, mark where we are and return. 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 25062306a36Sopenharmony_ci i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff); 25162306a36Sopenharmony_ci *rtblock = start - i + 1; 25262306a36Sopenharmony_ci return 0; 25362306a36Sopenharmony_ci } else 25462306a36Sopenharmony_ci i = len; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci /* 25762306a36Sopenharmony_ci * No match, return that we scanned the whole area. 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 26062306a36Sopenharmony_ci *rtblock = start - i + 1; 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/* 26562306a36Sopenharmony_ci * Searching forward from start to limit, find the first block whose 26662306a36Sopenharmony_ci * allocated/free state is different from start's. 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_ciint 26962306a36Sopenharmony_cixfs_rtfind_forw( 27062306a36Sopenharmony_ci xfs_mount_t *mp, /* file system mount point */ 27162306a36Sopenharmony_ci xfs_trans_t *tp, /* transaction pointer */ 27262306a36Sopenharmony_ci xfs_rtblock_t start, /* starting block to look at */ 27362306a36Sopenharmony_ci xfs_rtblock_t limit, /* last block to look at */ 27462306a36Sopenharmony_ci xfs_rtblock_t *rtblock) /* out: start block found */ 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci xfs_rtword_t *b; /* current word in buffer */ 27762306a36Sopenharmony_ci int bit; /* bit number in the word */ 27862306a36Sopenharmony_ci xfs_rtblock_t block; /* bitmap block number */ 27962306a36Sopenharmony_ci struct xfs_buf *bp; /* buf for the block */ 28062306a36Sopenharmony_ci xfs_rtword_t *bufp; /* starting word in buffer */ 28162306a36Sopenharmony_ci int error; /* error value */ 28262306a36Sopenharmony_ci xfs_rtblock_t i; /* current bit number rel. to start */ 28362306a36Sopenharmony_ci xfs_rtblock_t lastbit; /* last useful bit in the word */ 28462306a36Sopenharmony_ci xfs_rtblock_t len; /* length of inspected area */ 28562306a36Sopenharmony_ci xfs_rtword_t mask; /* mask of relevant bits for value */ 28662306a36Sopenharmony_ci xfs_rtword_t want; /* mask for "good" values */ 28762306a36Sopenharmony_ci xfs_rtword_t wdiff; /* difference from wanted value */ 28862306a36Sopenharmony_ci int word; /* word number in the buffer */ 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* 29162306a36Sopenharmony_ci * Compute and read in starting bitmap block for starting block. 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_ci block = XFS_BITTOBLOCK(mp, start); 29462306a36Sopenharmony_ci error = xfs_rtbuf_get(mp, tp, block, 0, &bp); 29562306a36Sopenharmony_ci if (error) { 29662306a36Sopenharmony_ci return error; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci bufp = bp->b_addr; 29962306a36Sopenharmony_ci /* 30062306a36Sopenharmony_ci * Get the first word's index & point to it. 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_ci word = XFS_BITTOWORD(mp, start); 30362306a36Sopenharmony_ci b = &bufp[word]; 30462306a36Sopenharmony_ci bit = (int)(start & (XFS_NBWORD - 1)); 30562306a36Sopenharmony_ci len = limit - start + 1; 30662306a36Sopenharmony_ci /* 30762306a36Sopenharmony_ci * Compute match value, based on the bit at start: if 1 (free) 30862306a36Sopenharmony_ci * then all-ones, else all-zeroes. 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_ci want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0; 31162306a36Sopenharmony_ci /* 31262306a36Sopenharmony_ci * If the starting position is not word-aligned, deal with the 31362306a36Sopenharmony_ci * partial word. 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_ci if (bit) { 31662306a36Sopenharmony_ci /* 31762306a36Sopenharmony_ci * Calculate last (rightmost) bit number to look at, 31862306a36Sopenharmony_ci * and mask for all the relevant bits in this word. 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_ci lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); 32162306a36Sopenharmony_ci mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; 32262306a36Sopenharmony_ci /* 32362306a36Sopenharmony_ci * Calculate the difference between the value there 32462306a36Sopenharmony_ci * and what we're looking for. 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_ci if ((wdiff = (*b ^ want) & mask)) { 32762306a36Sopenharmony_ci /* 32862306a36Sopenharmony_ci * Different. Mark where we are and return. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 33162306a36Sopenharmony_ci i = XFS_RTLOBIT(wdiff) - bit; 33262306a36Sopenharmony_ci *rtblock = start + i - 1; 33362306a36Sopenharmony_ci return 0; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci i = lastbit - bit; 33662306a36Sopenharmony_ci /* 33762306a36Sopenharmony_ci * Go on to next block if that's where the next word is 33862306a36Sopenharmony_ci * and we need the next word. 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_ci if (++word == XFS_BLOCKWSIZE(mp) && i < len) { 34162306a36Sopenharmony_ci /* 34262306a36Sopenharmony_ci * If done with this block, get the previous one. 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 34562306a36Sopenharmony_ci error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); 34662306a36Sopenharmony_ci if (error) { 34762306a36Sopenharmony_ci return error; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci b = bufp = bp->b_addr; 35062306a36Sopenharmony_ci word = 0; 35162306a36Sopenharmony_ci } else { 35262306a36Sopenharmony_ci /* 35362306a36Sopenharmony_ci * Go on to the previous word in the buffer. 35462306a36Sopenharmony_ci */ 35562306a36Sopenharmony_ci b++; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci } else { 35862306a36Sopenharmony_ci /* 35962306a36Sopenharmony_ci * Starting on a word boundary, no partial word. 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_ci i = 0; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci /* 36462306a36Sopenharmony_ci * Loop over whole words in buffers. When we use up one buffer 36562306a36Sopenharmony_ci * we move on to the next one. 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_ci while (len - i >= XFS_NBWORD) { 36862306a36Sopenharmony_ci /* 36962306a36Sopenharmony_ci * Compute difference between actual and desired value. 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_ci if ((wdiff = *b ^ want)) { 37262306a36Sopenharmony_ci /* 37362306a36Sopenharmony_ci * Different, mark where we are and return. 37462306a36Sopenharmony_ci */ 37562306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 37662306a36Sopenharmony_ci i += XFS_RTLOBIT(wdiff); 37762306a36Sopenharmony_ci *rtblock = start + i - 1; 37862306a36Sopenharmony_ci return 0; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci i += XFS_NBWORD; 38162306a36Sopenharmony_ci /* 38262306a36Sopenharmony_ci * Go on to next block if that's where the next word is 38362306a36Sopenharmony_ci * and we need the next word. 38462306a36Sopenharmony_ci */ 38562306a36Sopenharmony_ci if (++word == XFS_BLOCKWSIZE(mp) && i < len) { 38662306a36Sopenharmony_ci /* 38762306a36Sopenharmony_ci * If done with this block, get the next one. 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 39062306a36Sopenharmony_ci error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); 39162306a36Sopenharmony_ci if (error) { 39262306a36Sopenharmony_ci return error; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci b = bufp = bp->b_addr; 39562306a36Sopenharmony_ci word = 0; 39662306a36Sopenharmony_ci } else { 39762306a36Sopenharmony_ci /* 39862306a36Sopenharmony_ci * Go on to the next word in the buffer. 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_ci b++; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci /* 40462306a36Sopenharmony_ci * If not ending on a word boundary, deal with the last 40562306a36Sopenharmony_ci * (partial) word. 40662306a36Sopenharmony_ci */ 40762306a36Sopenharmony_ci if ((lastbit = len - i)) { 40862306a36Sopenharmony_ci /* 40962306a36Sopenharmony_ci * Calculate mask for all the relevant bits in this word. 41062306a36Sopenharmony_ci */ 41162306a36Sopenharmony_ci mask = ((xfs_rtword_t)1 << lastbit) - 1; 41262306a36Sopenharmony_ci /* 41362306a36Sopenharmony_ci * Compute difference between actual and desired value. 41462306a36Sopenharmony_ci */ 41562306a36Sopenharmony_ci if ((wdiff = (*b ^ want) & mask)) { 41662306a36Sopenharmony_ci /* 41762306a36Sopenharmony_ci * Different, mark where we are and return. 41862306a36Sopenharmony_ci */ 41962306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 42062306a36Sopenharmony_ci i += XFS_RTLOBIT(wdiff); 42162306a36Sopenharmony_ci *rtblock = start + i - 1; 42262306a36Sopenharmony_ci return 0; 42362306a36Sopenharmony_ci } else 42462306a36Sopenharmony_ci i = len; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci /* 42762306a36Sopenharmony_ci * No match, return that we scanned the whole area. 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 43062306a36Sopenharmony_ci *rtblock = start + i - 1; 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci/* 43562306a36Sopenharmony_ci * Read and/or modify the summary information for a given extent size, 43662306a36Sopenharmony_ci * bitmap block combination. 43762306a36Sopenharmony_ci * Keeps track of a current summary block, so we don't keep reading 43862306a36Sopenharmony_ci * it from the buffer cache. 43962306a36Sopenharmony_ci * 44062306a36Sopenharmony_ci * Summary information is returned in *sum if specified. 44162306a36Sopenharmony_ci * If no delta is specified, returns summary only. 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_ciint 44462306a36Sopenharmony_cixfs_rtmodify_summary_int( 44562306a36Sopenharmony_ci xfs_mount_t *mp, /* file system mount structure */ 44662306a36Sopenharmony_ci xfs_trans_t *tp, /* transaction pointer */ 44762306a36Sopenharmony_ci int log, /* log2 of extent size */ 44862306a36Sopenharmony_ci xfs_rtblock_t bbno, /* bitmap block number */ 44962306a36Sopenharmony_ci int delta, /* change to make to summary info */ 45062306a36Sopenharmony_ci struct xfs_buf **rbpp, /* in/out: summary block buffer */ 45162306a36Sopenharmony_ci xfs_fsblock_t *rsb, /* in/out: summary block number */ 45262306a36Sopenharmony_ci xfs_suminfo_t *sum) /* out: summary info for this block */ 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct xfs_buf *bp; /* buffer for the summary block */ 45562306a36Sopenharmony_ci int error; /* error value */ 45662306a36Sopenharmony_ci xfs_fsblock_t sb; /* summary fsblock */ 45762306a36Sopenharmony_ci int so; /* index into the summary file */ 45862306a36Sopenharmony_ci xfs_suminfo_t *sp; /* pointer to returned data */ 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* 46162306a36Sopenharmony_ci * Compute entry number in the summary file. 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_ci so = XFS_SUMOFFS(mp, log, bbno); 46462306a36Sopenharmony_ci /* 46562306a36Sopenharmony_ci * Compute the block number in the summary file. 46662306a36Sopenharmony_ci */ 46762306a36Sopenharmony_ci sb = XFS_SUMOFFSTOBLOCK(mp, so); 46862306a36Sopenharmony_ci /* 46962306a36Sopenharmony_ci * If we have an old buffer, and the block number matches, use that. 47062306a36Sopenharmony_ci */ 47162306a36Sopenharmony_ci if (*rbpp && *rsb == sb) 47262306a36Sopenharmony_ci bp = *rbpp; 47362306a36Sopenharmony_ci /* 47462306a36Sopenharmony_ci * Otherwise we have to get the buffer. 47562306a36Sopenharmony_ci */ 47662306a36Sopenharmony_ci else { 47762306a36Sopenharmony_ci /* 47862306a36Sopenharmony_ci * If there was an old one, get rid of it first. 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_ci if (*rbpp) 48162306a36Sopenharmony_ci xfs_trans_brelse(tp, *rbpp); 48262306a36Sopenharmony_ci error = xfs_rtbuf_get(mp, tp, sb, 1, &bp); 48362306a36Sopenharmony_ci if (error) { 48462306a36Sopenharmony_ci return error; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci /* 48762306a36Sopenharmony_ci * Remember this buffer and block for the next call. 48862306a36Sopenharmony_ci */ 48962306a36Sopenharmony_ci *rbpp = bp; 49062306a36Sopenharmony_ci *rsb = sb; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci /* 49362306a36Sopenharmony_ci * Point to the summary information, modify/log it, and/or copy it out. 49462306a36Sopenharmony_ci */ 49562306a36Sopenharmony_ci sp = XFS_SUMPTR(mp, bp, so); 49662306a36Sopenharmony_ci if (delta) { 49762306a36Sopenharmony_ci uint first = (uint)((char *)sp - (char *)bp->b_addr); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci *sp += delta; 50062306a36Sopenharmony_ci if (mp->m_rsum_cache) { 50162306a36Sopenharmony_ci if (*sp == 0 && log == mp->m_rsum_cache[bbno]) 50262306a36Sopenharmony_ci mp->m_rsum_cache[bbno]++; 50362306a36Sopenharmony_ci if (*sp != 0 && log < mp->m_rsum_cache[bbno]) 50462306a36Sopenharmony_ci mp->m_rsum_cache[bbno] = log; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci xfs_trans_log_buf(tp, bp, first, first + sizeof(*sp) - 1); 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci if (sum) 50962306a36Sopenharmony_ci *sum = *sp; 51062306a36Sopenharmony_ci return 0; 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ciint 51462306a36Sopenharmony_cixfs_rtmodify_summary( 51562306a36Sopenharmony_ci xfs_mount_t *mp, /* file system mount structure */ 51662306a36Sopenharmony_ci xfs_trans_t *tp, /* transaction pointer */ 51762306a36Sopenharmony_ci int log, /* log2 of extent size */ 51862306a36Sopenharmony_ci xfs_rtblock_t bbno, /* bitmap block number */ 51962306a36Sopenharmony_ci int delta, /* change to make to summary info */ 52062306a36Sopenharmony_ci struct xfs_buf **rbpp, /* in/out: summary block buffer */ 52162306a36Sopenharmony_ci xfs_fsblock_t *rsb) /* in/out: summary block number */ 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci return xfs_rtmodify_summary_int(mp, tp, log, bbno, 52462306a36Sopenharmony_ci delta, rbpp, rsb, NULL); 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci/* 52862306a36Sopenharmony_ci * Set the given range of bitmap bits to the given value. 52962306a36Sopenharmony_ci * Do whatever I/O and logging is required. 53062306a36Sopenharmony_ci */ 53162306a36Sopenharmony_ciint 53262306a36Sopenharmony_cixfs_rtmodify_range( 53362306a36Sopenharmony_ci xfs_mount_t *mp, /* file system mount point */ 53462306a36Sopenharmony_ci xfs_trans_t *tp, /* transaction pointer */ 53562306a36Sopenharmony_ci xfs_rtblock_t start, /* starting block to modify */ 53662306a36Sopenharmony_ci xfs_extlen_t len, /* length of extent to modify */ 53762306a36Sopenharmony_ci int val) /* 1 for free, 0 for allocated */ 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci xfs_rtword_t *b; /* current word in buffer */ 54062306a36Sopenharmony_ci int bit; /* bit number in the word */ 54162306a36Sopenharmony_ci xfs_rtblock_t block; /* bitmap block number */ 54262306a36Sopenharmony_ci struct xfs_buf *bp; /* buf for the block */ 54362306a36Sopenharmony_ci xfs_rtword_t *bufp; /* starting word in buffer */ 54462306a36Sopenharmony_ci int error; /* error value */ 54562306a36Sopenharmony_ci xfs_rtword_t *first; /* first used word in the buffer */ 54662306a36Sopenharmony_ci int i; /* current bit number rel. to start */ 54762306a36Sopenharmony_ci int lastbit; /* last useful bit in word */ 54862306a36Sopenharmony_ci xfs_rtword_t mask; /* mask o frelevant bits for value */ 54962306a36Sopenharmony_ci int word; /* word number in the buffer */ 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* 55262306a36Sopenharmony_ci * Compute starting bitmap block number. 55362306a36Sopenharmony_ci */ 55462306a36Sopenharmony_ci block = XFS_BITTOBLOCK(mp, start); 55562306a36Sopenharmony_ci /* 55662306a36Sopenharmony_ci * Read the bitmap block, and point to its data. 55762306a36Sopenharmony_ci */ 55862306a36Sopenharmony_ci error = xfs_rtbuf_get(mp, tp, block, 0, &bp); 55962306a36Sopenharmony_ci if (error) { 56062306a36Sopenharmony_ci return error; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci bufp = bp->b_addr; 56362306a36Sopenharmony_ci /* 56462306a36Sopenharmony_ci * Compute the starting word's address, and starting bit. 56562306a36Sopenharmony_ci */ 56662306a36Sopenharmony_ci word = XFS_BITTOWORD(mp, start); 56762306a36Sopenharmony_ci first = b = &bufp[word]; 56862306a36Sopenharmony_ci bit = (int)(start & (XFS_NBWORD - 1)); 56962306a36Sopenharmony_ci /* 57062306a36Sopenharmony_ci * 0 (allocated) => all zeroes; 1 (free) => all ones. 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_ci val = -val; 57362306a36Sopenharmony_ci /* 57462306a36Sopenharmony_ci * If not starting on a word boundary, deal with the first 57562306a36Sopenharmony_ci * (partial) word. 57662306a36Sopenharmony_ci */ 57762306a36Sopenharmony_ci if (bit) { 57862306a36Sopenharmony_ci /* 57962306a36Sopenharmony_ci * Compute first bit not changed and mask of relevant bits. 58062306a36Sopenharmony_ci */ 58162306a36Sopenharmony_ci lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); 58262306a36Sopenharmony_ci mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; 58362306a36Sopenharmony_ci /* 58462306a36Sopenharmony_ci * Set/clear the active bits. 58562306a36Sopenharmony_ci */ 58662306a36Sopenharmony_ci if (val) 58762306a36Sopenharmony_ci *b |= mask; 58862306a36Sopenharmony_ci else 58962306a36Sopenharmony_ci *b &= ~mask; 59062306a36Sopenharmony_ci i = lastbit - bit; 59162306a36Sopenharmony_ci /* 59262306a36Sopenharmony_ci * Go on to the next block if that's where the next word is 59362306a36Sopenharmony_ci * and we need the next word. 59462306a36Sopenharmony_ci */ 59562306a36Sopenharmony_ci if (++word == XFS_BLOCKWSIZE(mp) && i < len) { 59662306a36Sopenharmony_ci /* 59762306a36Sopenharmony_ci * Log the changed part of this block. 59862306a36Sopenharmony_ci * Get the next one. 59962306a36Sopenharmony_ci */ 60062306a36Sopenharmony_ci xfs_trans_log_buf(tp, bp, 60162306a36Sopenharmony_ci (uint)((char *)first - (char *)bufp), 60262306a36Sopenharmony_ci (uint)((char *)b - (char *)bufp)); 60362306a36Sopenharmony_ci error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); 60462306a36Sopenharmony_ci if (error) { 60562306a36Sopenharmony_ci return error; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci first = b = bufp = bp->b_addr; 60862306a36Sopenharmony_ci word = 0; 60962306a36Sopenharmony_ci } else { 61062306a36Sopenharmony_ci /* 61162306a36Sopenharmony_ci * Go on to the next word in the buffer 61262306a36Sopenharmony_ci */ 61362306a36Sopenharmony_ci b++; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci } else { 61662306a36Sopenharmony_ci /* 61762306a36Sopenharmony_ci * Starting on a word boundary, no partial word. 61862306a36Sopenharmony_ci */ 61962306a36Sopenharmony_ci i = 0; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci /* 62262306a36Sopenharmony_ci * Loop over whole words in buffers. When we use up one buffer 62362306a36Sopenharmony_ci * we move on to the next one. 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_ci while (len - i >= XFS_NBWORD) { 62662306a36Sopenharmony_ci /* 62762306a36Sopenharmony_ci * Set the word value correctly. 62862306a36Sopenharmony_ci */ 62962306a36Sopenharmony_ci *b = val; 63062306a36Sopenharmony_ci i += XFS_NBWORD; 63162306a36Sopenharmony_ci /* 63262306a36Sopenharmony_ci * Go on to the next block if that's where the next word is 63362306a36Sopenharmony_ci * and we need the next word. 63462306a36Sopenharmony_ci */ 63562306a36Sopenharmony_ci if (++word == XFS_BLOCKWSIZE(mp) && i < len) { 63662306a36Sopenharmony_ci /* 63762306a36Sopenharmony_ci * Log the changed part of this block. 63862306a36Sopenharmony_ci * Get the next one. 63962306a36Sopenharmony_ci */ 64062306a36Sopenharmony_ci xfs_trans_log_buf(tp, bp, 64162306a36Sopenharmony_ci (uint)((char *)first - (char *)bufp), 64262306a36Sopenharmony_ci (uint)((char *)b - (char *)bufp)); 64362306a36Sopenharmony_ci error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); 64462306a36Sopenharmony_ci if (error) { 64562306a36Sopenharmony_ci return error; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci first = b = bufp = bp->b_addr; 64862306a36Sopenharmony_ci word = 0; 64962306a36Sopenharmony_ci } else { 65062306a36Sopenharmony_ci /* 65162306a36Sopenharmony_ci * Go on to the next word in the buffer 65262306a36Sopenharmony_ci */ 65362306a36Sopenharmony_ci b++; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci /* 65762306a36Sopenharmony_ci * If not ending on a word boundary, deal with the last 65862306a36Sopenharmony_ci * (partial) word. 65962306a36Sopenharmony_ci */ 66062306a36Sopenharmony_ci if ((lastbit = len - i)) { 66162306a36Sopenharmony_ci /* 66262306a36Sopenharmony_ci * Compute a mask of relevant bits. 66362306a36Sopenharmony_ci */ 66462306a36Sopenharmony_ci mask = ((xfs_rtword_t)1 << lastbit) - 1; 66562306a36Sopenharmony_ci /* 66662306a36Sopenharmony_ci * Set/clear the active bits. 66762306a36Sopenharmony_ci */ 66862306a36Sopenharmony_ci if (val) 66962306a36Sopenharmony_ci *b |= mask; 67062306a36Sopenharmony_ci else 67162306a36Sopenharmony_ci *b &= ~mask; 67262306a36Sopenharmony_ci b++; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci /* 67562306a36Sopenharmony_ci * Log any remaining changed bytes. 67662306a36Sopenharmony_ci */ 67762306a36Sopenharmony_ci if (b > first) 67862306a36Sopenharmony_ci xfs_trans_log_buf(tp, bp, (uint)((char *)first - (char *)bufp), 67962306a36Sopenharmony_ci (uint)((char *)b - (char *)bufp - 1)); 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci/* 68462306a36Sopenharmony_ci * Mark an extent specified by start and len freed. 68562306a36Sopenharmony_ci * Updates all the summary information as well as the bitmap. 68662306a36Sopenharmony_ci */ 68762306a36Sopenharmony_ciint 68862306a36Sopenharmony_cixfs_rtfree_range( 68962306a36Sopenharmony_ci xfs_mount_t *mp, /* file system mount point */ 69062306a36Sopenharmony_ci xfs_trans_t *tp, /* transaction pointer */ 69162306a36Sopenharmony_ci xfs_rtblock_t start, /* starting block to free */ 69262306a36Sopenharmony_ci xfs_extlen_t len, /* length to free */ 69362306a36Sopenharmony_ci struct xfs_buf **rbpp, /* in/out: summary block buffer */ 69462306a36Sopenharmony_ci xfs_fsblock_t *rsb) /* in/out: summary block number */ 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci xfs_rtblock_t end; /* end of the freed extent */ 69762306a36Sopenharmony_ci int error; /* error value */ 69862306a36Sopenharmony_ci xfs_rtblock_t postblock; /* first block freed > end */ 69962306a36Sopenharmony_ci xfs_rtblock_t preblock; /* first block freed < start */ 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci end = start + len - 1; 70262306a36Sopenharmony_ci /* 70362306a36Sopenharmony_ci * Modify the bitmap to mark this extent freed. 70462306a36Sopenharmony_ci */ 70562306a36Sopenharmony_ci error = xfs_rtmodify_range(mp, tp, start, len, 1); 70662306a36Sopenharmony_ci if (error) { 70762306a36Sopenharmony_ci return error; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci /* 71062306a36Sopenharmony_ci * Assume we're freeing out of the middle of an allocated extent. 71162306a36Sopenharmony_ci * We need to find the beginning and end of the extent so we can 71262306a36Sopenharmony_ci * properly update the summary. 71362306a36Sopenharmony_ci */ 71462306a36Sopenharmony_ci error = xfs_rtfind_back(mp, tp, start, 0, &preblock); 71562306a36Sopenharmony_ci if (error) { 71662306a36Sopenharmony_ci return error; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci /* 71962306a36Sopenharmony_ci * Find the next allocated block (end of allocated extent). 72062306a36Sopenharmony_ci */ 72162306a36Sopenharmony_ci error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1, 72262306a36Sopenharmony_ci &postblock); 72362306a36Sopenharmony_ci if (error) 72462306a36Sopenharmony_ci return error; 72562306a36Sopenharmony_ci /* 72662306a36Sopenharmony_ci * If there are blocks not being freed at the front of the 72762306a36Sopenharmony_ci * old extent, add summary data for them to be allocated. 72862306a36Sopenharmony_ci */ 72962306a36Sopenharmony_ci if (preblock < start) { 73062306a36Sopenharmony_ci error = xfs_rtmodify_summary(mp, tp, 73162306a36Sopenharmony_ci XFS_RTBLOCKLOG(start - preblock), 73262306a36Sopenharmony_ci XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb); 73362306a36Sopenharmony_ci if (error) { 73462306a36Sopenharmony_ci return error; 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci /* 73862306a36Sopenharmony_ci * If there are blocks not being freed at the end of the 73962306a36Sopenharmony_ci * old extent, add summary data for them to be allocated. 74062306a36Sopenharmony_ci */ 74162306a36Sopenharmony_ci if (postblock > end) { 74262306a36Sopenharmony_ci error = xfs_rtmodify_summary(mp, tp, 74362306a36Sopenharmony_ci XFS_RTBLOCKLOG(postblock - end), 74462306a36Sopenharmony_ci XFS_BITTOBLOCK(mp, end + 1), -1, rbpp, rsb); 74562306a36Sopenharmony_ci if (error) { 74662306a36Sopenharmony_ci return error; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci /* 75062306a36Sopenharmony_ci * Increment the summary information corresponding to the entire 75162306a36Sopenharmony_ci * (new) free extent. 75262306a36Sopenharmony_ci */ 75362306a36Sopenharmony_ci error = xfs_rtmodify_summary(mp, tp, 75462306a36Sopenharmony_ci XFS_RTBLOCKLOG(postblock + 1 - preblock), 75562306a36Sopenharmony_ci XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb); 75662306a36Sopenharmony_ci return error; 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci/* 76062306a36Sopenharmony_ci * Check that the given range is either all allocated (val = 0) or 76162306a36Sopenharmony_ci * all free (val = 1). 76262306a36Sopenharmony_ci */ 76362306a36Sopenharmony_ciint 76462306a36Sopenharmony_cixfs_rtcheck_range( 76562306a36Sopenharmony_ci xfs_mount_t *mp, /* file system mount point */ 76662306a36Sopenharmony_ci xfs_trans_t *tp, /* transaction pointer */ 76762306a36Sopenharmony_ci xfs_rtblock_t start, /* starting block number of extent */ 76862306a36Sopenharmony_ci xfs_extlen_t len, /* length of extent */ 76962306a36Sopenharmony_ci int val, /* 1 for free, 0 for allocated */ 77062306a36Sopenharmony_ci xfs_rtblock_t *new, /* out: first block not matching */ 77162306a36Sopenharmony_ci int *stat) /* out: 1 for matches, 0 for not */ 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci xfs_rtword_t *b; /* current word in buffer */ 77462306a36Sopenharmony_ci int bit; /* bit number in the word */ 77562306a36Sopenharmony_ci xfs_rtblock_t block; /* bitmap block number */ 77662306a36Sopenharmony_ci struct xfs_buf *bp; /* buf for the block */ 77762306a36Sopenharmony_ci xfs_rtword_t *bufp; /* starting word in buffer */ 77862306a36Sopenharmony_ci int error; /* error value */ 77962306a36Sopenharmony_ci xfs_rtblock_t i; /* current bit number rel. to start */ 78062306a36Sopenharmony_ci xfs_rtblock_t lastbit; /* last useful bit in word */ 78162306a36Sopenharmony_ci xfs_rtword_t mask; /* mask of relevant bits for value */ 78262306a36Sopenharmony_ci xfs_rtword_t wdiff; /* difference from wanted value */ 78362306a36Sopenharmony_ci int word; /* word number in the buffer */ 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* 78662306a36Sopenharmony_ci * Compute starting bitmap block number 78762306a36Sopenharmony_ci */ 78862306a36Sopenharmony_ci block = XFS_BITTOBLOCK(mp, start); 78962306a36Sopenharmony_ci /* 79062306a36Sopenharmony_ci * Read the bitmap block. 79162306a36Sopenharmony_ci */ 79262306a36Sopenharmony_ci error = xfs_rtbuf_get(mp, tp, block, 0, &bp); 79362306a36Sopenharmony_ci if (error) { 79462306a36Sopenharmony_ci return error; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci bufp = bp->b_addr; 79762306a36Sopenharmony_ci /* 79862306a36Sopenharmony_ci * Compute the starting word's address, and starting bit. 79962306a36Sopenharmony_ci */ 80062306a36Sopenharmony_ci word = XFS_BITTOWORD(mp, start); 80162306a36Sopenharmony_ci b = &bufp[word]; 80262306a36Sopenharmony_ci bit = (int)(start & (XFS_NBWORD - 1)); 80362306a36Sopenharmony_ci /* 80462306a36Sopenharmony_ci * 0 (allocated) => all zero's; 1 (free) => all one's. 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_ci val = -val; 80762306a36Sopenharmony_ci /* 80862306a36Sopenharmony_ci * If not starting on a word boundary, deal with the first 80962306a36Sopenharmony_ci * (partial) word. 81062306a36Sopenharmony_ci */ 81162306a36Sopenharmony_ci if (bit) { 81262306a36Sopenharmony_ci /* 81362306a36Sopenharmony_ci * Compute first bit not examined. 81462306a36Sopenharmony_ci */ 81562306a36Sopenharmony_ci lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); 81662306a36Sopenharmony_ci /* 81762306a36Sopenharmony_ci * Mask of relevant bits. 81862306a36Sopenharmony_ci */ 81962306a36Sopenharmony_ci mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; 82062306a36Sopenharmony_ci /* 82162306a36Sopenharmony_ci * Compute difference between actual and desired value. 82262306a36Sopenharmony_ci */ 82362306a36Sopenharmony_ci if ((wdiff = (*b ^ val) & mask)) { 82462306a36Sopenharmony_ci /* 82562306a36Sopenharmony_ci * Different, compute first wrong bit and return. 82662306a36Sopenharmony_ci */ 82762306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 82862306a36Sopenharmony_ci i = XFS_RTLOBIT(wdiff) - bit; 82962306a36Sopenharmony_ci *new = start + i; 83062306a36Sopenharmony_ci *stat = 0; 83162306a36Sopenharmony_ci return 0; 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci i = lastbit - bit; 83462306a36Sopenharmony_ci /* 83562306a36Sopenharmony_ci * Go on to next block if that's where the next word is 83662306a36Sopenharmony_ci * and we need the next word. 83762306a36Sopenharmony_ci */ 83862306a36Sopenharmony_ci if (++word == XFS_BLOCKWSIZE(mp) && i < len) { 83962306a36Sopenharmony_ci /* 84062306a36Sopenharmony_ci * If done with this block, get the next one. 84162306a36Sopenharmony_ci */ 84262306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 84362306a36Sopenharmony_ci error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); 84462306a36Sopenharmony_ci if (error) { 84562306a36Sopenharmony_ci return error; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci b = bufp = bp->b_addr; 84862306a36Sopenharmony_ci word = 0; 84962306a36Sopenharmony_ci } else { 85062306a36Sopenharmony_ci /* 85162306a36Sopenharmony_ci * Go on to the next word in the buffer. 85262306a36Sopenharmony_ci */ 85362306a36Sopenharmony_ci b++; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci } else { 85662306a36Sopenharmony_ci /* 85762306a36Sopenharmony_ci * Starting on a word boundary, no partial word. 85862306a36Sopenharmony_ci */ 85962306a36Sopenharmony_ci i = 0; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci /* 86262306a36Sopenharmony_ci * Loop over whole words in buffers. When we use up one buffer 86362306a36Sopenharmony_ci * we move on to the next one. 86462306a36Sopenharmony_ci */ 86562306a36Sopenharmony_ci while (len - i >= XFS_NBWORD) { 86662306a36Sopenharmony_ci /* 86762306a36Sopenharmony_ci * Compute difference between actual and desired value. 86862306a36Sopenharmony_ci */ 86962306a36Sopenharmony_ci if ((wdiff = *b ^ val)) { 87062306a36Sopenharmony_ci /* 87162306a36Sopenharmony_ci * Different, compute first wrong bit and return. 87262306a36Sopenharmony_ci */ 87362306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 87462306a36Sopenharmony_ci i += XFS_RTLOBIT(wdiff); 87562306a36Sopenharmony_ci *new = start + i; 87662306a36Sopenharmony_ci *stat = 0; 87762306a36Sopenharmony_ci return 0; 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci i += XFS_NBWORD; 88062306a36Sopenharmony_ci /* 88162306a36Sopenharmony_ci * Go on to next block if that's where the next word is 88262306a36Sopenharmony_ci * and we need the next word. 88362306a36Sopenharmony_ci */ 88462306a36Sopenharmony_ci if (++word == XFS_BLOCKWSIZE(mp) && i < len) { 88562306a36Sopenharmony_ci /* 88662306a36Sopenharmony_ci * If done with this block, get the next one. 88762306a36Sopenharmony_ci */ 88862306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 88962306a36Sopenharmony_ci error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); 89062306a36Sopenharmony_ci if (error) { 89162306a36Sopenharmony_ci return error; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci b = bufp = bp->b_addr; 89462306a36Sopenharmony_ci word = 0; 89562306a36Sopenharmony_ci } else { 89662306a36Sopenharmony_ci /* 89762306a36Sopenharmony_ci * Go on to the next word in the buffer. 89862306a36Sopenharmony_ci */ 89962306a36Sopenharmony_ci b++; 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci /* 90362306a36Sopenharmony_ci * If not ending on a word boundary, deal with the last 90462306a36Sopenharmony_ci * (partial) word. 90562306a36Sopenharmony_ci */ 90662306a36Sopenharmony_ci if ((lastbit = len - i)) { 90762306a36Sopenharmony_ci /* 90862306a36Sopenharmony_ci * Mask of relevant bits. 90962306a36Sopenharmony_ci */ 91062306a36Sopenharmony_ci mask = ((xfs_rtword_t)1 << lastbit) - 1; 91162306a36Sopenharmony_ci /* 91262306a36Sopenharmony_ci * Compute difference between actual and desired value. 91362306a36Sopenharmony_ci */ 91462306a36Sopenharmony_ci if ((wdiff = (*b ^ val) & mask)) { 91562306a36Sopenharmony_ci /* 91662306a36Sopenharmony_ci * Different, compute first wrong bit and return. 91762306a36Sopenharmony_ci */ 91862306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 91962306a36Sopenharmony_ci i += XFS_RTLOBIT(wdiff); 92062306a36Sopenharmony_ci *new = start + i; 92162306a36Sopenharmony_ci *stat = 0; 92262306a36Sopenharmony_ci return 0; 92362306a36Sopenharmony_ci } else 92462306a36Sopenharmony_ci i = len; 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci /* 92762306a36Sopenharmony_ci * Successful, return. 92862306a36Sopenharmony_ci */ 92962306a36Sopenharmony_ci xfs_trans_brelse(tp, bp); 93062306a36Sopenharmony_ci *new = start + i; 93162306a36Sopenharmony_ci *stat = 1; 93262306a36Sopenharmony_ci return 0; 93362306a36Sopenharmony_ci} 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci#ifdef DEBUG 93662306a36Sopenharmony_ci/* 93762306a36Sopenharmony_ci * Check that the given extent (block range) is allocated already. 93862306a36Sopenharmony_ci */ 93962306a36Sopenharmony_ciSTATIC int /* error */ 94062306a36Sopenharmony_cixfs_rtcheck_alloc_range( 94162306a36Sopenharmony_ci xfs_mount_t *mp, /* file system mount point */ 94262306a36Sopenharmony_ci xfs_trans_t *tp, /* transaction pointer */ 94362306a36Sopenharmony_ci xfs_rtblock_t bno, /* starting block number of extent */ 94462306a36Sopenharmony_ci xfs_extlen_t len) /* length of extent */ 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci xfs_rtblock_t new; /* dummy for xfs_rtcheck_range */ 94762306a36Sopenharmony_ci int stat; 94862306a36Sopenharmony_ci int error; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci error = xfs_rtcheck_range(mp, tp, bno, len, 0, &new, &stat); 95162306a36Sopenharmony_ci if (error) 95262306a36Sopenharmony_ci return error; 95362306a36Sopenharmony_ci ASSERT(stat); 95462306a36Sopenharmony_ci return 0; 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci#else 95762306a36Sopenharmony_ci#define xfs_rtcheck_alloc_range(m,t,b,l) (0) 95862306a36Sopenharmony_ci#endif 95962306a36Sopenharmony_ci/* 96062306a36Sopenharmony_ci * Free an extent in the realtime subvolume. Length is expressed in 96162306a36Sopenharmony_ci * realtime extents, as is the block number. 96262306a36Sopenharmony_ci */ 96362306a36Sopenharmony_ciint /* error */ 96462306a36Sopenharmony_cixfs_rtfree_extent( 96562306a36Sopenharmony_ci xfs_trans_t *tp, /* transaction pointer */ 96662306a36Sopenharmony_ci xfs_rtblock_t bno, /* starting block number to free */ 96762306a36Sopenharmony_ci xfs_extlen_t len) /* length of extent freed */ 96862306a36Sopenharmony_ci{ 96962306a36Sopenharmony_ci int error; /* error value */ 97062306a36Sopenharmony_ci xfs_mount_t *mp; /* file system mount structure */ 97162306a36Sopenharmony_ci xfs_fsblock_t sb; /* summary file block number */ 97262306a36Sopenharmony_ci struct xfs_buf *sumbp = NULL; /* summary file block buffer */ 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci mp = tp->t_mountp; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci ASSERT(mp->m_rbmip->i_itemp != NULL); 97762306a36Sopenharmony_ci ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL)); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci error = xfs_rtcheck_alloc_range(mp, tp, bno, len); 98062306a36Sopenharmony_ci if (error) 98162306a36Sopenharmony_ci return error; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci /* 98462306a36Sopenharmony_ci * Free the range of realtime blocks. 98562306a36Sopenharmony_ci */ 98662306a36Sopenharmony_ci error = xfs_rtfree_range(mp, tp, bno, len, &sumbp, &sb); 98762306a36Sopenharmony_ci if (error) { 98862306a36Sopenharmony_ci return error; 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci /* 99162306a36Sopenharmony_ci * Mark more blocks free in the superblock. 99262306a36Sopenharmony_ci */ 99362306a36Sopenharmony_ci xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, (long)len); 99462306a36Sopenharmony_ci /* 99562306a36Sopenharmony_ci * If we've now freed all the blocks, reset the file sequence 99662306a36Sopenharmony_ci * number to 0. 99762306a36Sopenharmony_ci */ 99862306a36Sopenharmony_ci if (tp->t_frextents_delta + mp->m_sb.sb_frextents == 99962306a36Sopenharmony_ci mp->m_sb.sb_rextents) { 100062306a36Sopenharmony_ci if (!(mp->m_rbmip->i_diflags & XFS_DIFLAG_NEWRTBM)) 100162306a36Sopenharmony_ci mp->m_rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM; 100262306a36Sopenharmony_ci *(uint64_t *)&VFS_I(mp->m_rbmip)->i_atime = 0; 100362306a36Sopenharmony_ci xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE); 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci return 0; 100662306a36Sopenharmony_ci} 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci/* 100962306a36Sopenharmony_ci * Free some blocks in the realtime subvolume. rtbno and rtlen are in units of 101062306a36Sopenharmony_ci * rt blocks, not rt extents; must be aligned to the rt extent size; and rtlen 101162306a36Sopenharmony_ci * cannot exceed XFS_MAX_BMBT_EXTLEN. 101262306a36Sopenharmony_ci */ 101362306a36Sopenharmony_ciint 101462306a36Sopenharmony_cixfs_rtfree_blocks( 101562306a36Sopenharmony_ci struct xfs_trans *tp, 101662306a36Sopenharmony_ci xfs_fsblock_t rtbno, 101762306a36Sopenharmony_ci xfs_filblks_t rtlen) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci struct xfs_mount *mp = tp->t_mountp; 102062306a36Sopenharmony_ci xfs_rtblock_t bno; 102162306a36Sopenharmony_ci xfs_filblks_t len; 102262306a36Sopenharmony_ci xfs_extlen_t mod; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci ASSERT(rtlen <= XFS_MAX_BMBT_EXTLEN); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci len = div_u64_rem(rtlen, mp->m_sb.sb_rextsize, &mod); 102762306a36Sopenharmony_ci if (mod) { 102862306a36Sopenharmony_ci ASSERT(mod == 0); 102962306a36Sopenharmony_ci return -EIO; 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci bno = div_u64_rem(rtbno, mp->m_sb.sb_rextsize, &mod); 103362306a36Sopenharmony_ci if (mod) { 103462306a36Sopenharmony_ci ASSERT(mod == 0); 103562306a36Sopenharmony_ci return -EIO; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci return xfs_rtfree_extent(tp, bno, len); 103962306a36Sopenharmony_ci} 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci/* Find all the free records within a given range. */ 104262306a36Sopenharmony_ciint 104362306a36Sopenharmony_cixfs_rtalloc_query_range( 104462306a36Sopenharmony_ci struct xfs_mount *mp, 104562306a36Sopenharmony_ci struct xfs_trans *tp, 104662306a36Sopenharmony_ci const struct xfs_rtalloc_rec *low_rec, 104762306a36Sopenharmony_ci const struct xfs_rtalloc_rec *high_rec, 104862306a36Sopenharmony_ci xfs_rtalloc_query_range_fn fn, 104962306a36Sopenharmony_ci void *priv) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci struct xfs_rtalloc_rec rec; 105262306a36Sopenharmony_ci xfs_rtblock_t rtstart; 105362306a36Sopenharmony_ci xfs_rtblock_t rtend; 105462306a36Sopenharmony_ci xfs_rtblock_t high_key; 105562306a36Sopenharmony_ci int is_free; 105662306a36Sopenharmony_ci int error = 0; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci if (low_rec->ar_startext > high_rec->ar_startext) 105962306a36Sopenharmony_ci return -EINVAL; 106062306a36Sopenharmony_ci if (low_rec->ar_startext >= mp->m_sb.sb_rextents || 106162306a36Sopenharmony_ci low_rec->ar_startext == high_rec->ar_startext) 106262306a36Sopenharmony_ci return 0; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci high_key = min(high_rec->ar_startext, mp->m_sb.sb_rextents - 1); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci /* Iterate the bitmap, looking for discrepancies. */ 106762306a36Sopenharmony_ci rtstart = low_rec->ar_startext; 106862306a36Sopenharmony_ci while (rtstart <= high_key) { 106962306a36Sopenharmony_ci /* Is the first block free? */ 107062306a36Sopenharmony_ci error = xfs_rtcheck_range(mp, tp, rtstart, 1, 1, &rtend, 107162306a36Sopenharmony_ci &is_free); 107262306a36Sopenharmony_ci if (error) 107362306a36Sopenharmony_ci break; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* How long does the extent go for? */ 107662306a36Sopenharmony_ci error = xfs_rtfind_forw(mp, tp, rtstart, high_key, &rtend); 107762306a36Sopenharmony_ci if (error) 107862306a36Sopenharmony_ci break; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (is_free) { 108162306a36Sopenharmony_ci rec.ar_startext = rtstart; 108262306a36Sopenharmony_ci rec.ar_extcount = rtend - rtstart + 1; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci error = fn(mp, tp, &rec, priv); 108562306a36Sopenharmony_ci if (error) 108662306a36Sopenharmony_ci break; 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci rtstart = rtend + 1; 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci return error; 109362306a36Sopenharmony_ci} 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci/* Find all the free records. */ 109662306a36Sopenharmony_ciint 109762306a36Sopenharmony_cixfs_rtalloc_query_all( 109862306a36Sopenharmony_ci struct xfs_mount *mp, 109962306a36Sopenharmony_ci struct xfs_trans *tp, 110062306a36Sopenharmony_ci xfs_rtalloc_query_range_fn fn, 110162306a36Sopenharmony_ci void *priv) 110262306a36Sopenharmony_ci{ 110362306a36Sopenharmony_ci struct xfs_rtalloc_rec keys[2]; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci keys[0].ar_startext = 0; 110662306a36Sopenharmony_ci keys[1].ar_startext = mp->m_sb.sb_rextents - 1; 110762306a36Sopenharmony_ci keys[0].ar_extcount = keys[1].ar_extcount = 0; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci return xfs_rtalloc_query_range(mp, tp, &keys[0], &keys[1], fn, priv); 111062306a36Sopenharmony_ci} 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci/* Is the given extent all free? */ 111362306a36Sopenharmony_ciint 111462306a36Sopenharmony_cixfs_rtalloc_extent_is_free( 111562306a36Sopenharmony_ci struct xfs_mount *mp, 111662306a36Sopenharmony_ci struct xfs_trans *tp, 111762306a36Sopenharmony_ci xfs_rtblock_t start, 111862306a36Sopenharmony_ci xfs_extlen_t len, 111962306a36Sopenharmony_ci bool *is_free) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci xfs_rtblock_t end; 112262306a36Sopenharmony_ci int matches; 112362306a36Sopenharmony_ci int error; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci error = xfs_rtcheck_range(mp, tp, start, len, 1, &end, &matches); 112662306a36Sopenharmony_ci if (error) 112762306a36Sopenharmony_ci return error; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci *is_free = matches; 113062306a36Sopenharmony_ci return 0; 113162306a36Sopenharmony_ci} 1132