|
Packit Service |
360c39 |
#include "clusterautoconfig.h"
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#include <inttypes.h>
|
|
Packit Service |
360c39 |
#include <limits.h>
|
|
Packit Service |
360c39 |
#include <stdio.h>
|
|
Packit Service |
360c39 |
#include <stdlib.h>
|
|
Packit Service |
360c39 |
#include <string.h>
|
|
Packit Service |
360c39 |
#include <unistd.h>
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#include "libgfs2.h"
|
|
Packit Service |
360c39 |
#include "rgrp.h"
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#define RG_SYNC_TOLERANCE 1000
|
|
Packit Service |
360c39 |
#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static void compute_bitmaps(lgfs2_rgrp_t rg, const unsigned bsize)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int x;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rg->bits[0].bi_offset = sizeof(struct gfs2_rgrp);
|
|
Packit Service |
360c39 |
rg->bits[0].bi_start = 0;
|
|
Packit Service |
360c39 |
rg->bits[0].bi_len = bsize - sizeof(struct gfs2_rgrp);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (x = 1; x < rg->ri.ri_length; x++) {
|
|
Packit Service |
360c39 |
rg->bits[x].bi_offset = sizeof(struct gfs2_meta_header);
|
|
Packit Service |
360c39 |
rg->bits[x].bi_start = rg->bits[x - 1].bi_start + rg->bits[x - 1].bi_len;
|
|
Packit Service |
360c39 |
rg->bits[x].bi_len = bsize - sizeof(struct gfs2_meta_header);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
x--;
|
|
Packit Service |
360c39 |
rg->bits[x].bi_len = rg->ri.ri_bitbytes - rg->bits[x].bi_start;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* gfs2_compute_bitstructs - Compute the bitmap sizes
|
|
Packit Service |
360c39 |
* bsize: Block size
|
|
Packit Service |
360c39 |
* rgd: The resource group descriptor
|
|
Packit Service |
360c39 |
* Returns: 0 on success, -1 on error
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int gfs2_compute_bitstructs(const uint32_t bsize, struct rgrp_tree *rgd)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint32_t length = rgd->ri.ri_length;
|
|
Packit Service |
360c39 |
uint32_t bytes_left;
|
|
Packit Service |
360c39 |
int ownbits = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Max size of an rg is 2GB. A 2GB RG with (minimum) 512-byte blocks
|
|
Packit Service |
360c39 |
has 4194304 blocks. We can represent 4 blocks in one bitmap byte.
|
|
Packit Service |
360c39 |
Therefore, all 4194304 blocks can be represented in 1048576 bytes.
|
|
Packit Service |
360c39 |
Subtract a metadata header for each 512-byte block and we get
|
|
Packit Service |
360c39 |
488 bytes of bitmap per block. Divide 1048576 by 488 and we can
|
|
Packit Service |
360c39 |
be assured we should never have more than 2149 of them. */
|
|
Packit Service |
360c39 |
errno = EINVAL;
|
|
Packit Service |
360c39 |
if (length > 2149 || length == 0)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if(rgd->bits == NULL) {
|
|
Packit Service |
360c39 |
rgd->bits = calloc(length, sizeof(struct gfs2_bitmap));
|
|
Packit Service |
360c39 |
if(rgd->bits == NULL)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
ownbits = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
compute_bitmaps(rgd, bsize);
|
|
Packit Service |
360c39 |
bytes_left = rgd->ri.ri_bitbytes - (rgd->bits[rgd->ri.ri_length - 1].bi_start +
|
|
Packit Service |
360c39 |
rgd->bits[rgd->ri.ri_length - 1].bi_len);
|
|
Packit Service |
360c39 |
errno = EINVAL;
|
|
Packit Service |
360c39 |
if(bytes_left)
|
|
Packit Service |
360c39 |
goto errbits;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if((rgd->bits[length - 1].bi_start +
|
|
Packit Service |
360c39 |
rgd->bits[length - 1].bi_len) * GFS2_NBBY != rgd->ri.ri_data)
|
|
Packit Service |
360c39 |
goto errbits;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
errbits:
|
|
Packit Service |
360c39 |
if (ownbits) {
|
|
Packit Service |
360c39 |
free(rgd->bits);
|
|
Packit Service |
360c39 |
rgd->bits = NULL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* blk2rgrpd - Find resource group for a given data block number
|
|
Packit Service |
360c39 |
* @sdp: The GFS superblock
|
|
Packit Service |
360c39 |
* @n: The data block number
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: Ths resource group, or NULL if not found
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
struct rgrp_tree *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, uint64_t blk)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct rgrp_tree *rgd = (struct rgrp_tree *)sdp->rgtree.osi_node;
|
|
Packit Service |
360c39 |
while (rgd) {
|
|
Packit Service |
360c39 |
if (blk < rgd->ri.ri_addr)
|
|
Packit Service |
360c39 |
rgd = (struct rgrp_tree *)rgd->node.osi_left;
|
|
Packit Service |
360c39 |
else if (blk >= rgd->ri.ri_data0 + rgd->ri.ri_data)
|
|
Packit Service |
360c39 |
rgd = (struct rgrp_tree *)rgd->node.osi_right;
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
return rgd;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Allocate a multi-block buffer for a resource group's bitmaps. This is done
|
|
Packit Service |
360c39 |
* as one chunk and should be freed using lgfs2_rgrp_bitbuf_free().
|
|
Packit Service |
360c39 |
* Returns 0 on success with the bitmap buffer allocated in the resource group,
|
|
Packit Service |
360c39 |
* or non-zero on failure with errno set.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int lgfs2_rgrp_bitbuf_alloc(lgfs2_rgrp_t rg)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = rg->rgrps->sdp;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bhs;
|
|
Packit Service |
360c39 |
size_t len = rg->ri.ri_length * sdp->bsize;
|
|
Packit Service |
360c39 |
unsigned long io_align = sdp->bsize;
|
|
Packit Service |
360c39 |
unsigned i;
|
|
Packit Service |
360c39 |
char *bufs;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (rg->rgrps->align > 0) {
|
|
Packit Service |
360c39 |
len = ROUND_UP(len, rg->rgrps->align * sdp->bsize);
|
|
Packit Service |
360c39 |
io_align = rg->rgrps->align_off * sdp->bsize;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
bhs = calloc(rg->ri.ri_length, sizeof(struct gfs2_buffer_head));
|
|
Packit Service |
360c39 |
if (bhs == NULL)
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (posix_memalign((void **)&bufs, io_align, len) != 0) {
|
|
Packit Service |
360c39 |
errno = ENOMEM;
|
|
Packit Service |
360c39 |
free(bhs);
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
memset(bufs, 0, len);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (i = 0; i < rg->ri.ri_length; i++) {
|
|
Packit Service |
360c39 |
rg->bits[i].bi_bh = bhs + i;
|
|
Packit Service |
360c39 |
rg->bits[i].bi_bh->iov.iov_base = bufs + (i * sdp->bsize);
|
|
Packit Service |
360c39 |
rg->bits[i].bi_bh->iov.iov_len = sdp->bsize;
|
|
Packit Service |
360c39 |
rg->bits[i].bi_bh->b_blocknr = rg->ri.ri_addr + i;
|
|
Packit Service |
360c39 |
rg->bits[i].bi_bh->sdp = sdp;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Free the multi-block bitmap buffer from a resource group. The buffer should
|
|
Packit Service |
360c39 |
* have been allocated as a single chunk as in lgfs2_rgrp_bitbuf_alloc().
|
|
Packit Service |
360c39 |
* This does not implicitly write the bitmaps to disk. Use lgfs2_rgrp_write()
|
|
Packit Service |
360c39 |
* for that.
|
|
Packit Service |
360c39 |
* rg: The resource groups whose bitmap buffer should be freed.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
void lgfs2_rgrp_bitbuf_free(lgfs2_rgrp_t rg)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
unsigned i;
|
|
Packit Service |
360c39 |
free(rg->bits[0].bi_bh->iov.iov_base);
|
|
Packit Service |
360c39 |
free(rg->bits[0].bi_bh);
|
|
Packit Service |
360c39 |
for (i = 0; i < rg->ri.ri_length; i++)
|
|
Packit Service |
360c39 |
rg->bits[i].bi_bh = NULL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Check a resource group's crc
|
|
Packit Service |
360c39 |
* Returns 0 on success, non-zero if crc is bad
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int lgfs2_rgrp_crc_check(char *buf)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int ret = 0;
|
|
Packit Service |
360c39 |
#ifdef GFS2_HAS_RG_RI_FIELDS
|
|
Packit Service |
360c39 |
struct gfs2_rgrp *rg = (struct gfs2_rgrp *)buf;
|
|
Packit Service |
360c39 |
uint32_t crc = rg->rg_crc;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (crc == 0)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rg->rg_crc = 0;
|
|
Packit Service |
360c39 |
if (be32_to_cpu(crc) != gfs2_disk_hash(buf, sizeof(struct gfs2_rgrp)))
|
|
Packit Service |
360c39 |
ret = 1;
|
|
Packit Service |
360c39 |
rg->rg_crc = crc;
|
|
Packit Service |
360c39 |
#endif
|
|
Packit Service |
360c39 |
return ret;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Set the crc of an on-disk resource group
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
void lgfs2_rgrp_crc_set(char *buf)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
#ifdef GFS2_HAS_RG_RI_FIELDS
|
|
Packit Service |
360c39 |
struct gfs2_rgrp *rg = (struct gfs2_rgrp *)buf;
|
|
Packit Service |
360c39 |
uint32_t crc;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rg->rg_crc = 0;
|
|
Packit Service |
360c39 |
crc = gfs2_disk_hash(buf, sizeof(struct gfs2_rgrp));
|
|
Packit Service |
360c39 |
rg->rg_crc = cpu_to_be32(crc);
|
|
Packit Service |
360c39 |
#endif
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* gfs2_rgrp_read - read in the resource group information from disk.
|
|
Packit Service |
360c39 |
* @rgd - resource group structure
|
|
Packit Service |
360c39 |
* returns: 0 if no error, otherwise the block number that failed
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
uint64_t gfs2_rgrp_read(struct gfs2_sbd *sdp, struct rgrp_tree *rgd)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
unsigned x, length = rgd->ri.ri_length;
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bhs;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (length == 0 || gfs2_check_range(sdp, rgd->ri.ri_addr))
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bhs = calloc(length, sizeof(struct gfs2_buffer_head *));
|
|
Packit Service |
360c39 |
if (bhs == NULL)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (breadm(sdp, bhs, length, rgd->ri.ri_addr)) {
|
|
Packit Service |
360c39 |
free(bhs);
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (x = 0; x < length; x++) {
|
|
Packit Service |
360c39 |
struct gfs2_bitmap *bi = &rgd->bits[x];
|
|
Packit Service |
360c39 |
int mtype = (x ? GFS2_METATYPE_RB : GFS2_METATYPE_RG);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
bi->bi_bh = bhs[x];
|
|
Packit Service |
360c39 |
if (gfs2_check_meta(bi->bi_bh, mtype)) {
|
|
Packit Service |
360c39 |
unsigned err = x;
|
|
Packit Service |
360c39 |
do {
|
|
Packit Service |
360c39 |
brelse(rgd->bits[x].bi_bh);
|
|
Packit Service |
360c39 |
rgd->bits[x].bi_bh = NULL;
|
|
Packit Service |
360c39 |
} while (x-- != 0);
|
|
Packit Service |
360c39 |
free(bhs);
|
|
Packit Service |
360c39 |
return rgd->ri.ri_addr + err;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (sdp->gfs1)
|
|
Packit Service |
360c39 |
gfs_rgrp_in((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
|
|
Packit Service |
360c39 |
else {
|
|
Packit Service |
360c39 |
if (lgfs2_rgrp_crc_check(rgd->bits[0].bi_bh->b_data)) {
|
|
Packit Service |
360c39 |
free(bhs);
|
|
Packit Service |
360c39 |
return rgd->ri.ri_addr;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
gfs2_rgrp_in(&rgd->rg, rgd->bits[0].bi_bh->b_data);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
free(bhs);
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
void gfs2_rgrp_relse(struct rgrp_tree *rgd)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int x, length = rgd->ri.ri_length;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (rgd->bits == NULL)
|
|
Packit Service |
360c39 |
return;
|
|
Packit Service |
360c39 |
for (x = 0; x < length; x++) {
|
|
Packit Service |
360c39 |
if (rgd->bits[x].bi_bh && rgd->bits[x].bi_bh->b_data) {
|
|
Packit Service |
360c39 |
brelse(rgd->bits[x].bi_bh);
|
|
Packit Service |
360c39 |
rgd->bits[x].bi_bh = NULL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
struct rgrp_tree *rgrp_insert(struct osi_root *rgtree, uint64_t rgblock)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct osi_node **newn = &rgtree->osi_node, *parent = NULL;
|
|
Packit Service |
360c39 |
struct rgrp_tree *data;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Figure out where to put new node */
|
|
Packit Service |
360c39 |
while (*newn) {
|
|
Packit Service |
360c39 |
struct rgrp_tree *cur = (struct rgrp_tree *)*newn;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
parent = *newn;
|
|
Packit Service |
360c39 |
if (rgblock < cur->ri.ri_addr)
|
|
Packit Service |
360c39 |
newn = &((*newn)->osi_left);
|
|
Packit Service |
360c39 |
else if (rgblock > cur->ri.ri_addr)
|
|
Packit Service |
360c39 |
newn = &((*newn)->osi_right);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
return cur;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
data = calloc(1, sizeof(struct rgrp_tree));
|
|
Packit Service |
360c39 |
if (!data)
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
/* Add new node and rebalance tree. */
|
|
Packit Service |
360c39 |
data->ri.ri_addr = rgblock;
|
|
Packit Service |
360c39 |
osi_link_node(&data->node, parent, newn);
|
|
Packit Service |
360c39 |
osi_insert_color(&data->node, rgtree);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return data;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
void gfs2_rgrp_free(struct osi_root *rgrp_tree)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct rgrp_tree *rgd;
|
|
Packit Service |
360c39 |
int rgs_since_sync = 0;
|
|
Packit Service |
360c39 |
struct osi_node *n;
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (OSI_EMPTY_ROOT(rgrp_tree))
|
|
Packit Service |
360c39 |
return;
|
|
Packit Service |
360c39 |
while ((n = osi_first(rgrp_tree))) {
|
|
Packit Service |
360c39 |
rgd = (struct rgrp_tree *)n;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (rgd->bits) {
|
|
Packit Service |
360c39 |
if (rgd->bits[0].bi_bh) { /* if a buffer exists */
|
|
Packit Service |
360c39 |
rgs_since_sync++;
|
|
Packit Service |
360c39 |
if (rgs_since_sync >= RG_SYNC_TOLERANCE) {
|
|
Packit Service |
360c39 |
if (!sdp)
|
|
Packit Service |
360c39 |
sdp = rgd->bits[0].bi_bh->sdp;
|
|
Packit Service |
360c39 |
fsync(sdp->device_fd);
|
|
Packit Service |
360c39 |
rgs_since_sync = 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
gfs2_rgrp_relse(rgd); /* free them all. */
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
free(rgd->bits);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
osi_erase(&rgd->node, rgrp_tree);
|
|
Packit Service |
360c39 |
free(rgd);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static uint64_t align_block(const uint64_t base, const uint64_t align)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
if ((align > 0) && ((base % align) > 0))
|
|
Packit Service |
360c39 |
return (base - (base % align)) + align;
|
|
Packit Service |
360c39 |
return base;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Calculate the aligned block address of a resource group.
|
|
Packit Service |
360c39 |
* rgs: The resource groups handle
|
|
Packit Service |
360c39 |
* base: The base address of the first resource group address, in blocks
|
|
Packit Service |
360c39 |
* Returns the aligned address of the first resource group.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
uint64_t lgfs2_rgrp_align_addr(const lgfs2_rgrps_t rgs, uint64_t addr)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return align_block(addr, rgs->align);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Calculate the aligned relative address of the next resource group (and thus
|
|
Packit Service |
360c39 |
* the aligned length of this one).
|
|
Packit Service |
360c39 |
* rgs: The resource groups handle
|
|
Packit Service |
360c39 |
* base: The base length of the current resource group, in blocks
|
|
Packit Service |
360c39 |
* Returns the length of the resource group (the aligned relative address of
|
|
Packit Service |
360c39 |
* the next one)
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
uint32_t lgfs2_rgrp_align_len(const lgfs2_rgrps_t rgs, uint32_t len)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return align_block(len, rgs->align) + rgs->align_off;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Plan the sizes of resource groups for remaining free space, based on a
|
|
Packit Service |
360c39 |
* target maximum size. In order to make best use of the space while keeping
|
|
Packit Service |
360c39 |
* the resource groups aligned appropriately we need to either reduce the
|
|
Packit Service |
360c39 |
* length of every resource group or of a subset of the resource groups, so
|
|
Packit Service |
360c39 |
* we're left with either one or two resource group sizes. We keep track of
|
|
Packit Service |
360c39 |
* both of these and the numbers of each size of resource group inside the
|
|
Packit Service |
360c39 |
* resource groups descriptor.
|
|
Packit Service |
360c39 |
* rgs: The resource groups descriptor
|
|
Packit Service |
360c39 |
* space: The number of remaining blocks to be allocated
|
|
Packit Service |
360c39 |
* tgtsize: The target resource group size in blocks
|
|
Packit Service |
360c39 |
* Returns the number of resource groups planned to fit in the given space, or
|
|
Packit Service |
360c39 |
* 0 if the smallest resource group would be smaller than GFS2_MIN_RGSIZE.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
uint32_t lgfs2_rgrps_plan(const lgfs2_rgrps_t rgs, uint64_t space, uint32_t tgtsize)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint32_t maxlen = (GFS2_MAX_RGSIZE << 20) / rgs->sdp->bsize;
|
|
Packit Service |
360c39 |
uint32_t minlen = (GFS2_MIN_RGSIZE << 20) / rgs->sdp->bsize;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Apps should already have checked that the rg size is <=
|
|
Packit Service |
360c39 |
GFS2_MAX_RGSIZE but just in case alignment pushes it over we clamp
|
|
Packit Service |
360c39 |
it back down while calculating the initial rgrp length. */
|
|
Packit Service |
360c39 |
do {
|
|
Packit Service |
360c39 |
rgs->plan[0].len = lgfs2_rgrp_align_len(rgs, tgtsize);
|
|
Packit Service |
360c39 |
tgtsize -= (rgs->align + 1);
|
|
Packit Service |
360c39 |
} while (rgs->plan[0].len > maxlen);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rgs->plan[0].num = space / rgs->plan[0].len;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if ((space - (rgs->plan[0].num * rgs->plan[0].len)) > rgs->align) {
|
|
Packit Service |
360c39 |
unsigned adj = (rgs->align > 0) ? rgs->align : 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Spread the adjustment required to fit a new rgrp at the end
|
|
Packit Service |
360c39 |
over all of the rgrps so that we don't end with a single
|
|
Packit Service |
360c39 |
tiny one. */
|
|
Packit Service |
360c39 |
rgs->plan[0].num++;
|
|
Packit Service |
360c39 |
while (((rgs->plan[0].len - adj) * (uint64_t)rgs->plan[0].num) >= space)
|
|
Packit Service |
360c39 |
rgs->plan[0].len -= adj;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* We've adjusted the size of the rgrps down as far as we can
|
|
Packit Service |
360c39 |
without leaving a large gap at the end of the device now,
|
|
Packit Service |
360c39 |
but we still need to reduce the size of some rgrps in order
|
|
Packit Service |
360c39 |
to make everything fit, so we use the second rgplan to
|
|
Packit Service |
360c39 |
specify a second length for a subset of the resource groups.
|
|
Packit Service |
360c39 |
If plan[0].len already divides the space with no remainder,
|
|
Packit Service |
360c39 |
plan[1].num will stay 0 and it won't be used. */
|
|
Packit Service |
360c39 |
rgs->plan[1].len = rgs->plan[0].len - adj;
|
|
Packit Service |
360c39 |
rgs->plan[1].num = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while (((rgs->plan[0].len * rgs->plan[0].num) +
|
|
Packit Service |
360c39 |
(rgs->plan[1].len * rgs->plan[1].num)) >= space) {
|
|
Packit Service |
360c39 |
/* Total number of rgrps stays constant now. We just
|
|
Packit Service |
360c39 |
need to shift some weight around */
|
|
Packit Service |
360c39 |
rgs->plan[0].num--;
|
|
Packit Service |
360c39 |
rgs->plan[1].num++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Once we've reached this point,
|
|
Packit Service |
360c39 |
(plan[0].num * plan[0].len) + (plan[1].num * plan[1].len)
|
|
Packit Service |
360c39 |
will be less than one adjustment smaller than 'space'. */
|
|
Packit Service |
360c39 |
if (rgs->plan[0].len < minlen)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return rgs->plan[0].num + rgs->plan[1].num;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Create and initialise an empty set of resource groups
|
|
Packit Service |
360c39 |
* bsize: The block size of the fs
|
|
Packit Service |
360c39 |
* devlen: The length of the device, in fs blocks
|
|
Packit Service |
360c39 |
* align: The required stripe alignment of the resource groups. Must be a multiple of 'offset'.
|
|
Packit Service |
360c39 |
* offset: The required stripe offset of the resource groups
|
|
Packit Service |
360c39 |
* Returns an initialised lgfs2_rgrps_t or NULL if unsuccessful with errno set
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
lgfs2_rgrps_t lgfs2_rgrps_init(struct gfs2_sbd *sdp, uint64_t align, uint64_t offset)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
lgfs2_rgrps_t rgs;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
errno = EINVAL;
|
|
Packit Service |
360c39 |
if (offset != 0 && (align % offset) != 0)
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rgs = calloc(1, sizeof(*rgs));
|
|
Packit Service |
360c39 |
if (rgs == NULL)
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rgs->sdp = sdp;
|
|
Packit Service |
360c39 |
rgs->align = align;
|
|
Packit Service |
360c39 |
rgs->align_off = offset;
|
|
Packit Service |
360c39 |
memset(&rgs->root, 0, sizeof(rgs->root));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return rgs;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Populate a set of resource groups from a gfs2 rindex file.
|
|
Packit Service |
360c39 |
* fd: An open file descriptor for the rindex file.
|
|
Packit Service |
360c39 |
* rgs: The set of resource groups.
|
|
Packit Service |
360c39 |
* Returns the number of resource groups added to the set or 0 on error with
|
|
Packit Service |
360c39 |
* errno set.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
unsigned lgfs2_rindex_read_fd(int fd, lgfs2_rgrps_t rgs)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
unsigned count = 0;
|
|
Packit Service |
360c39 |
char buf[sizeof(struct gfs2_rindex)];
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
errno = EINVAL;
|
|
Packit Service |
360c39 |
if (fd < 0 || rgs == NULL)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while (1) {
|
|
Packit Service |
360c39 |
lgfs2_rgrp_t rg;
|
|
Packit Service |
360c39 |
struct gfs2_rindex ri;
|
|
Packit Service |
360c39 |
ssize_t ret = read(fd, buf, sizeof(struct gfs2_rindex));
|
|
Packit Service |
360c39 |
if (ret == 0)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (ret != sizeof(struct gfs2_rindex))
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gfs2_rindex_in(&ri, buf);
|
|
Packit Service |
360c39 |
rg = lgfs2_rgrps_append(rgs, &ri, 0);
|
|
Packit Service |
360c39 |
if (rg == NULL)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
count++;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return count;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Read a rindex entry into a set of resource groups
|
|
Packit Service |
360c39 |
* rip: The inode of the rindex file
|
|
Packit Service |
360c39 |
* rgs: The set of resource groups.
|
|
Packit Service |
360c39 |
* i: The index of the entry to read from the rindex file
|
|
Packit Service |
360c39 |
* Returns the new rindex entry added to the set or NULL on error with errno
|
|
Packit Service |
360c39 |
* set.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
const struct gfs2_rindex *lgfs2_rindex_read_one(struct gfs2_inode *rip, lgfs2_rgrps_t rgs, unsigned i)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint64_t off = i * sizeof(struct gfs2_rindex);
|
|
Packit Service |
360c39 |
char buf[sizeof(struct gfs2_rindex)];
|
|
Packit Service |
360c39 |
struct gfs2_rindex ri;
|
|
Packit Service |
360c39 |
lgfs2_rgrp_t rg;
|
|
Packit Service |
360c39 |
int ret;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
errno = EINVAL;
|
|
Packit Service |
360c39 |
if (rip == NULL || rgs == NULL)
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
ret = gfs2_readi(rip, buf, off, sizeof(struct gfs2_rindex));
|
|
Packit Service |
360c39 |
if (ret != sizeof(struct gfs2_rindex))
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gfs2_rindex_in(&ri, buf);
|
|
Packit Service |
360c39 |
rg = lgfs2_rgrps_append(rgs, &ri, 0);
|
|
Packit Service |
360c39 |
if (rg == NULL)
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return &rg->ri;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Free a set of resource groups created with lgfs2_rgrps_append() etc. This
|
|
Packit Service |
360c39 |
* does not write any dirty buffers to disk. See lgfs2_rgrp_write().
|
|
Packit Service |
360c39 |
* rgs: A pointer to the set of resource groups to be freed.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
void lgfs2_rgrps_free(lgfs2_rgrps_t *rgs)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
lgfs2_rgrp_t rg;
|
|
Packit Service |
360c39 |
struct osi_root *tree = &(*rgs)->root;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
while ((rg = (struct rgrp_tree *)osi_first(tree))) {
|
|
Packit Service |
360c39 |
int i;
|
|
Packit Service |
360c39 |
for (i = 0; i < rg->ri.ri_length; i++) {
|
|
Packit Service |
360c39 |
if (rg->bits[i].bi_bh != NULL) {
|
|
Packit Service |
360c39 |
free(rg->bits[i].bi_bh);
|
|
Packit Service |
360c39 |
rg->bits[i].bi_bh = NULL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
osi_erase(&rg->node, tree);
|
|
Packit Service |
360c39 |
free(rg);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
free(*rgs);
|
|
Packit Service |
360c39 |
*rgs = NULL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Calculate the fields for a new entry in the resource group index.
|
|
Packit Service |
360c39 |
* ri: A pointer to the resource group index entry to be calculated.
|
|
Packit Service |
360c39 |
* addr: The address at which to place this resource group
|
|
Packit Service |
360c39 |
* len: The required length of the resource group, in fs blocks.
|
|
Packit Service |
360c39 |
* If rglen is 0, geometry previously calculated by lgfs2_rgrps_plan() will be used.
|
|
Packit Service |
360c39 |
* Returns the calculated address of the next resource group or 0 with errno set:
|
|
Packit Service |
360c39 |
* EINVAL - The entry pointer is NULL
|
|
Packit Service |
360c39 |
* ENOSPC - This rgrp would extend past the end of the device
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
uint64_t lgfs2_rindex_entry_new(lgfs2_rgrps_t rgs, struct gfs2_rindex *ri, uint64_t addr, uint32_t len)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int plan = -1;
|
|
Packit Service |
360c39 |
errno = EINVAL;
|
|
Packit Service |
360c39 |
if (!ri)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
errno = ENOSPC;
|
|
Packit Service |
360c39 |
if (rgs->plan[0].num > 0)
|
|
Packit Service |
360c39 |
plan = 0;
|
|
Packit Service |
360c39 |
else if (rgs->plan[1].num > 0)
|
|
Packit Service |
360c39 |
plan = 1;
|
|
Packit Service |
360c39 |
else if (len == 0)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (plan >= 0 && (len == 0 || len == rgs->plan[plan].len)) {
|
|
Packit Service |
360c39 |
len = rgs->plan[plan].len;
|
|
Packit Service |
360c39 |
rgs->plan[plan].num--;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (addr + len > rgs->sdp->device.length)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
ri->ri_addr = addr;
|
|
Packit Service |
360c39 |
ri->ri_length = rgblocks2bitblocks(rgs->sdp->bsize, len, &ri->ri_data);
|
|
Packit Service |
360c39 |
ri->__pad = 0;
|
|
Packit Service |
360c39 |
ri->ri_data0 = ri->ri_addr + ri->ri_length;
|
|
Packit Service |
360c39 |
ri->ri_bitbytes = ri->ri_data / GFS2_NBBY;
|
|
Packit Service |
360c39 |
memset(&ri->ri_reserved, 0, sizeof(ri->ri_reserved));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return ri->ri_addr + len;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Return the rindex structure relating to a resource group.
|
|
Packit Service |
360c39 |
* The return type is const to advise callers that making changes to this
|
|
Packit Service |
360c39 |
* structure directly isn't wise. libgfs2 functions should be used instead.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
const struct gfs2_rindex *lgfs2_rgrp_index(lgfs2_rgrp_t rg)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return &rg->ri;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Return the rgrp structure relating to a resource group.
|
|
Packit Service |
360c39 |
* The return type is const to advise callers that making changes to this
|
|
Packit Service |
360c39 |
* structure directly isn't wise. libgfs2 functions should be used instead.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
const struct gfs2_rgrp *lgfs2_rgrp_rgrp(lgfs2_rgrp_t rg)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return &rg->rg;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Returns the total resource group size, in blocks, required to give blksreq data blocks
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
unsigned lgfs2_rgsize_for_data(uint64_t blksreq, unsigned bsize)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
const uint32_t blks_rgrp = GFS2_NBBY * (bsize - sizeof(struct gfs2_rgrp));
|
|
Packit Service |
360c39 |
const uint32_t blks_meta = GFS2_NBBY * (bsize - sizeof(struct gfs2_meta_header));
|
|
Packit Service |
360c39 |
unsigned bitblocks = 1;
|
|
Packit Service |
360c39 |
blksreq = (blksreq + 3) & ~3;
|
|
Packit Service |
360c39 |
if (blksreq > blks_rgrp)
|
|
Packit Service |
360c39 |
bitblocks += ((blksreq - blks_rgrp) + blks_meta - 1) / blks_meta;
|
|
Packit Service |
360c39 |
return bitblocks + blksreq;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
// Temporary function to aid in API migration
|
|
Packit Service |
360c39 |
struct osi_node *lgfs2_rgrps_root(lgfs2_rgrps_t rgs)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return rgs->root.osi_node;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Insert a new resource group after the last resource group in a set.
|
|
Packit Service |
360c39 |
* rgs: The set of resource groups
|
|
Packit Service |
360c39 |
* entry: The entry to be added
|
|
Packit Service |
360c39 |
* rg_skip: The value to be used for this resource group's rg_skip field
|
|
Packit Service |
360c39 |
* Returns the new resource group on success or NULL on failure with errno set.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
lgfs2_rgrp_t lgfs2_rgrps_append(lgfs2_rgrps_t rgs, struct gfs2_rindex *entry, uint32_t rg_skip)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
lgfs2_rgrp_t rg;
|
|
Packit Service |
360c39 |
struct osi_node **link = &rgs->root.osi_node;
|
|
Packit Service |
360c39 |
struct osi_node *parent = osi_last(&rgs->root);
|
|
Packit Service |
360c39 |
lgfs2_rgrp_t lastrg = (lgfs2_rgrp_t)parent;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
errno = EINVAL;
|
|
Packit Service |
360c39 |
if (entry == NULL)
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (lastrg != NULL) { /* Tree is not empty */
|
|
Packit Service |
360c39 |
if (entry->ri_addr <= lastrg->ri.ri_addr)
|
|
Packit Service |
360c39 |
return NULL; /* Appending with a lower address doesn't make sense */
|
|
Packit Service |
360c39 |
link = &lastrg->node.osi_right;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rg = calloc(1, sizeof(*rg) + (entry->ri_length * sizeof(struct gfs2_bitmap)));
|
|
Packit Service |
360c39 |
if (rg == NULL)
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rg->bits = (struct gfs2_bitmap *)(rg + 1);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
osi_link_node(&rg->node, parent, link);
|
|
Packit Service |
360c39 |
osi_insert_color(&rg->node, &rgs->root);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
memcpy(&rg->ri, entry, sizeof(struct gfs2_rindex));
|
|
Packit Service |
360c39 |
rg->rg.rg_header.mh_magic = GFS2_MAGIC;
|
|
Packit Service |
360c39 |
rg->rg.rg_header.mh_type = GFS2_METATYPE_RG;
|
|
Packit Service |
360c39 |
rg->rg.rg_header.mh_format = GFS2_FORMAT_RG;
|
|
Packit Service |
360c39 |
rg->rg.rg_free = rg->ri.ri_data;
|
|
Packit Service |
360c39 |
#ifdef GFS2_HAS_RG_SKIP
|
|
Packit Service |
360c39 |
rg->rg.rg_skip = rg_skip;
|
|
Packit Service |
360c39 |
#endif
|
|
Packit Service |
360c39 |
#ifdef GFS2_HAS_RG_RI_FIELDS
|
|
Packit Service |
360c39 |
rg->rg.rg_data0 = rg->ri.ri_data0;
|
|
Packit Service |
360c39 |
rg->rg.rg_data = rg->ri.ri_data;
|
|
Packit Service |
360c39 |
rg->rg.rg_bitbytes = rg->ri.ri_bitbytes;
|
|
Packit Service |
360c39 |
rg->rg.rg_crc = 0;
|
|
Packit Service |
360c39 |
#endif
|
|
Packit Service |
360c39 |
compute_bitmaps(rg, rgs->sdp->bsize);
|
|
Packit Service |
360c39 |
rg->rgrps = rgs;
|
|
Packit Service |
360c39 |
return rg;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* Write a resource group to a file descriptor.
|
|
Packit Service |
360c39 |
* Returns 0 on success or non-zero on failure with errno set
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int lgfs2_rgrp_write(int fd, const lgfs2_rgrp_t rg)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = rg->rgrps->sdp;
|
|
Packit Service |
360c39 |
unsigned int i;
|
|
Packit Service |
360c39 |
const struct gfs2_meta_header bmh = {
|
|
Packit Service |
360c39 |
.mh_magic = GFS2_MAGIC,
|
|
Packit Service |
360c39 |
.mh_type = GFS2_METATYPE_RB,
|
|
Packit Service |
360c39 |
.mh_format = GFS2_FORMAT_RB,
|
|
Packit Service |
360c39 |
};
|
|
Packit Service |
360c39 |
int freebufs = 0;
|
|
Packit Service |
360c39 |
ssize_t ret;
|
|
Packit Service |
360c39 |
size_t len;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (rg->bits[0].bi_bh == NULL) {
|
|
Packit Service |
360c39 |
freebufs = 1;
|
|
Packit Service |
360c39 |
if (lgfs2_rgrp_bitbuf_alloc(rg) != 0)
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
gfs2_rgrp_out(&rg->rg, rg->bits[0].bi_bh->b_data);
|
|
Packit Service |
360c39 |
for (i = 1; i < rg->ri.ri_length; i++)
|
|
Packit Service |
360c39 |
gfs2_meta_header_out(&bmh, rg->bits[i].bi_bh->b_data);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
len = sdp->bsize * rg->ri.ri_length;
|
|
Packit Service |
360c39 |
if (rg->rgrps->align > 0)
|
|
Packit Service |
360c39 |
len = ROUND_UP(len, rg->rgrps->align * sdp->bsize);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
ret = pwrite(sdp->device_fd, rg->bits[0].bi_bh->b_data, len,
|
|
Packit Service |
360c39 |
rg->bits[0].bi_bh->b_blocknr * sdp->bsize);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (freebufs)
|
|
Packit Service |
360c39 |
lgfs2_rgrp_bitbuf_free(rg);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return ret == len ? 0 : -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
lgfs2_rgrp_t lgfs2_rgrp_first(lgfs2_rgrps_t rgs)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return (lgfs2_rgrp_t)osi_first(&rgs->root);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
lgfs2_rgrp_t lgfs2_rgrp_next(lgfs2_rgrp_t rg)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return (lgfs2_rgrp_t)osi_next(&rg->node);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
lgfs2_rgrp_t lgfs2_rgrp_prev(lgfs2_rgrp_t rg)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return (lgfs2_rgrp_t)osi_prev(&rg->node);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
lgfs2_rgrp_t lgfs2_rgrp_last(lgfs2_rgrps_t rgs)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return (lgfs2_rgrp_t)osi_last(&rgs->root);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* gfs2_rbm_from_block - Set the rbm based upon rgd and block number
|
|
Packit Service |
360c39 |
* @rbm: The rbm with rgd already set correctly
|
|
Packit Service |
360c39 |
* @block: The block number (filesystem relative)
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* This sets the bi and offset members of an rbm based on a
|
|
Packit Service |
360c39 |
* resource group and a filesystem relative block number. The
|
|
Packit Service |
360c39 |
* resource group must be set in the rbm on entry, the bi and
|
|
Packit Service |
360c39 |
* offset members will be set by this function.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: 0 on success, or non-zero with errno set
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int lgfs2_rbm_from_block(struct lgfs2_rbm *rbm, uint64_t block)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint64_t rblock = block - rbm->rgd->ri.ri_data0;
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = rbm_bi(rbm)->bi_bh->sdp;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (rblock > UINT_MAX) {
|
|
Packit Service |
360c39 |
errno = EINVAL;
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (block >= rbm->rgd->ri.ri_data0 + rbm->rgd->ri.ri_data) {
|
|
Packit Service |
360c39 |
errno = E2BIG;
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rbm->bii = 0;
|
|
Packit Service |
360c39 |
rbm->offset = (uint32_t)(rblock);
|
|
Packit Service |
360c39 |
/* Check if the block is within the first block */
|
|
Packit Service |
360c39 |
if (rbm->offset < (rbm_bi(rbm)->bi_len * GFS2_NBBY))
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Adjust for the size diff between gfs2_meta_header and gfs2_rgrp */
|
|
Packit Service |
360c39 |
rbm->offset += (sizeof(struct gfs2_rgrp) -
|
|
Packit Service |
360c39 |
sizeof(struct gfs2_meta_header)) * GFS2_NBBY;
|
|
Packit Service |
360c39 |
rbm->bii = rbm->offset / sdp->sd_blocks_per_bitmap;
|
|
Packit Service |
360c39 |
rbm->offset -= rbm->bii * sdp->sd_blocks_per_bitmap;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* lgfs2_rbm_incr - increment an rbm structure
|
|
Packit Service |
360c39 |
* @rbm: The rbm with rgd already set correctly
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* This function takes an existing rbm structure and increments it to the next
|
|
Packit Service |
360c39 |
* viable block offset.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: If incrementing the offset would cause the rbm to go past the
|
|
Packit Service |
360c39 |
* end of the rgrp, true is returned, otherwise false.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int lgfs2_rbm_incr(struct lgfs2_rbm *rbm)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
if (rbm->offset + 1 < (rbm_bi(rbm)->bi_len * GFS2_NBBY)) { /* in the same bitmap */
|
|
Packit Service |
360c39 |
rbm->offset++;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (rbm->bii == rbm->rgd->ri.ri_length - 1) /* at the last bitmap */
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rbm->offset = 0;
|
|
Packit Service |
360c39 |
rbm->bii++;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* lgfs2_testbit - test a bit in the bitmaps
|
|
Packit Service |
360c39 |
* @rbm: The bit to test
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: The two bit block state of the requested bit
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static inline uint8_t lgfs2_testbit(const struct lgfs2_rbm *rbm)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_bitmap *bi = rbm_bi(rbm);
|
|
Packit Service |
360c39 |
const uint8_t *buffer = (uint8_t *)bi->bi_bh->b_data + bi->bi_offset;
|
|
Packit Service |
360c39 |
const uint8_t *byte;
|
|
Packit Service |
360c39 |
unsigned int bit;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
byte = buffer + (rbm->offset / GFS2_NBBY);
|
|
Packit Service |
360c39 |
bit = (rbm->offset % GFS2_NBBY) * GFS2_BIT_SIZE;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return (*byte >> bit) & GFS2_BIT_MASK;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* lgfs2_unaligned_extlen - Look for free blocks which are not byte aligned
|
|
Packit Service |
360c39 |
* @rbm: Position to search (value/result)
|
|
Packit Service |
360c39 |
* @n_unaligned: Number of unaligned blocks to check
|
|
Packit Service |
360c39 |
* @len: Decremented for each block found (terminate on zero)
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: true if a non-free block is encountered
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int lgfs2_unaligned_extlen(struct lgfs2_rbm *rbm, uint32_t n_unaligned, uint32_t *len)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint32_t n;
|
|
Packit Service |
360c39 |
uint8_t res;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (n = 0; n < n_unaligned; n++) {
|
|
Packit Service |
360c39 |
res = lgfs2_testbit(rbm);
|
|
Packit Service |
360c39 |
if (res != GFS2_BLKST_FREE)
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
(*len)--;
|
|
Packit Service |
360c39 |
if (*len == 0)
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
if (lgfs2_rbm_incr(rbm))
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static uint8_t *check_bytes8(const uint8_t *start, uint8_t value, unsigned bytes)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
while (bytes) {
|
|
Packit Service |
360c39 |
if (*start != value)
|
|
Packit Service |
360c39 |
return (void *)start;
|
|
Packit Service |
360c39 |
start++;
|
|
Packit Service |
360c39 |
bytes--;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* lgfs2_free_extlen - Return extent length of free blocks
|
|
Packit Service |
360c39 |
* @rbm: Starting position
|
|
Packit Service |
360c39 |
* @len: Max length to check
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Starting at the block specified by the rbm, see how many free blocks
|
|
Packit Service |
360c39 |
* there are, not reading more than len blocks ahead. This can be done
|
|
Packit Service |
360c39 |
* using check_bytes8 when the blocks are byte aligned, but has to be done
|
|
Packit Service |
360c39 |
* on a block by block basis in case of unaligned blocks. Also this
|
|
Packit Service |
360c39 |
* function can cope with bitmap boundaries (although it must stop on
|
|
Packit Service |
360c39 |
* a resource group boundary)
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: Number of free blocks in the extent
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static uint32_t lgfs2_free_extlen(const struct lgfs2_rbm *rrbm, uint32_t len)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct lgfs2_rbm rbm = *rrbm;
|
|
Packit Service |
360c39 |
uint32_t n_unaligned = rbm.offset & 3;
|
|
Packit Service |
360c39 |
uint32_t size = len;
|
|
Packit Service |
360c39 |
uint32_t bytes;
|
|
Packit Service |
360c39 |
uint32_t chunk_size;
|
|
Packit Service |
360c39 |
uint8_t *ptr, *start, *end;
|
|
Packit Service |
360c39 |
uint64_t block;
|
|
Packit Service |
360c39 |
struct gfs2_bitmap *bi;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (n_unaligned &&
|
|
Packit Service |
360c39 |
lgfs2_unaligned_extlen(&rbm, 4 - n_unaligned, &len))
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
n_unaligned = len & 3;
|
|
Packit Service |
360c39 |
/* Start is now byte aligned */
|
|
Packit Service |
360c39 |
while (len > 3) {
|
|
Packit Service |
360c39 |
bi = rbm_bi(&rbm;;
|
|
Packit Service |
360c39 |
start = (uint8_t *)bi->bi_bh->b_data;
|
|
Packit Service |
360c39 |
end = start + bi->bi_bh->sdp->bsize;
|
|
Packit Service |
360c39 |
start += bi->bi_offset;
|
|
Packit Service |
360c39 |
start += (rbm.offset / GFS2_NBBY);
|
|
Packit Service |
360c39 |
bytes = (len / GFS2_NBBY) < (end - start) ? (len / GFS2_NBBY):(end - start);
|
|
Packit Service |
360c39 |
ptr = check_bytes8(start, 0, bytes);
|
|
Packit Service |
360c39 |
chunk_size = ((ptr == NULL) ? bytes : (ptr - start));
|
|
Packit Service |
360c39 |
chunk_size *= GFS2_NBBY;
|
|
Packit Service |
360c39 |
len -= chunk_size;
|
|
Packit Service |
360c39 |
block = lgfs2_rbm_to_block(&rbm;;
|
|
Packit Service |
360c39 |
if (lgfs2_rbm_from_block(&rbm, block + chunk_size)) {
|
|
Packit Service |
360c39 |
n_unaligned = 0;
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (ptr) {
|
|
Packit Service |
360c39 |
n_unaligned = 3;
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
n_unaligned = len & 3;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Deal with any bits left over at the end */
|
|
Packit Service |
360c39 |
if (n_unaligned)
|
|
Packit Service |
360c39 |
lgfs2_unaligned_extlen(&rbm, n_unaligned, &len;;
|
|
Packit Service |
360c39 |
out:
|
|
Packit Service |
360c39 |
return size - len;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* gfs2_rbm_find - Look for blocks of a particular state
|
|
Packit Service |
360c39 |
* @rbm: Value/result starting position and final position
|
|
Packit Service |
360c39 |
* @state: The state which we want to find
|
|
Packit Service |
360c39 |
* @minext: Pointer to the requested extent length (NULL for a single block)
|
|
Packit Service |
360c39 |
* This is updated to be the actual reservation size.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: 0 on success, non-zero with errno == ENOSPC if there is no block of the requested state
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int lgfs2_rbm_find(struct lgfs2_rbm *rbm, uint8_t state, uint32_t *minext)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int initial_bii;
|
|
Packit Service |
360c39 |
uint32_t offset;
|
|
Packit Service |
360c39 |
int n = 0;
|
|
Packit Service |
360c39 |
int iters = rbm->rgd->ri.ri_length;
|
|
Packit Service |
360c39 |
uint32_t extlen;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* If we are not starting at the beginning of a bitmap, then we
|
|
Packit Service |
360c39 |
* need to add one to the bitmap count to ensure that we search
|
|
Packit Service |
360c39 |
* the starting bitmap twice.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
if (rbm->offset != 0)
|
|
Packit Service |
360c39 |
iters++;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (n = 0; n < iters; n++) {
|
|
Packit Service |
360c39 |
struct gfs2_bitmap *bi = rbm_bi(rbm);
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh = bi->bi_bh;
|
|
Packit Service |
360c39 |
uint8_t *buf = (uint8_t *)bh->b_data + bi->bi_offset;
|
|
Packit Service |
360c39 |
uint64_t block;
|
|
Packit Service |
360c39 |
int ret;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if ((rbm->rgd->rg.rg_free < *minext) && (state == GFS2_BLKST_FREE))
|
|
Packit Service |
360c39 |
goto next_bitmap;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
offset = gfs2_bitfit(buf, bi->bi_len, rbm->offset, state);
|
|
Packit Service |
360c39 |
if (offset == BFITNOENT)
|
|
Packit Service |
360c39 |
goto next_bitmap;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
rbm->offset = offset;
|
|
Packit Service |
360c39 |
initial_bii = rbm->bii;
|
|
Packit Service |
360c39 |
block = lgfs2_rbm_to_block(rbm);
|
|
Packit Service |
360c39 |
extlen = 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (*minext != 0)
|
|
Packit Service |
360c39 |
extlen = lgfs2_free_extlen(rbm, *minext);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (extlen >= *minext)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
ret = lgfs2_rbm_from_block(rbm, block + extlen);
|
|
Packit Service |
360c39 |
if (ret == 0) {
|
|
Packit Service |
360c39 |
n += (rbm->bii - initial_bii);
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (errno == E2BIG) {
|
|
Packit Service |
360c39 |
rbm->bii = 0;
|
|
Packit Service |
360c39 |
rbm->offset = 0;
|
|
Packit Service |
360c39 |
n += (rbm->bii - initial_bii);
|
|
Packit Service |
360c39 |
goto res_covered_end_of_rgrp;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return ret;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
next_bitmap: /* Find next bitmap in the rgrp */
|
|
Packit Service |
360c39 |
rbm->offset = 0;
|
|
Packit Service |
360c39 |
rbm->bii++;
|
|
Packit Service |
360c39 |
if (rbm->bii == rbm->rgd->ri.ri_length)
|
|
Packit Service |
360c39 |
rbm->bii = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
res_covered_end_of_rgrp:
|
|
Packit Service |
360c39 |
if (rbm->bii == 0)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
errno = ENOSPC;
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* lgfs2_alloc_extent - allocate an extent from a given bitmap
|
|
Packit Service |
360c39 |
* @rbm: the resource group information
|
|
Packit Service |
360c39 |
* @state: The state of the first block, GFS2_BLKST_DINODE or GFS2_BLKST_USED
|
|
Packit Service |
360c39 |
* @elen: The requested extent length
|
|
Packit Service |
360c39 |
* Returns the length of the extent allocated.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
unsigned lgfs2_alloc_extent(const struct lgfs2_rbm *rbm, int state, const unsigned elen)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct lgfs2_rbm pos = { .rgd = rbm->rgd, };
|
|
Packit Service |
360c39 |
const uint64_t block = lgfs2_rbm_to_block(rbm);
|
|
Packit Service |
360c39 |
unsigned len;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
gfs2_set_bitmap(rbm->rgd, block, state);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
for (len = 1; len < elen; len++) {
|
|
Packit Service |
360c39 |
int ret = lgfs2_rbm_from_block(&pos, block + len);
|
|
Packit Service |
360c39 |
if (ret || lgfs2_testbit(&pos) != GFS2_BLKST_FREE)
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
gfs2_set_bitmap(pos.rgd, block + len, GFS2_BLKST_USED);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return len;
|
|
Packit Service |
360c39 |
}
|