blob: d078286586e54cd4cb6920c5fb72254ddb96510a [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* This file is part of bcache tools.
* Copyright (c) 2020 SUSE Software Solutions
*
* Authors: Coly Li <colyli@suse.de>
*/
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include "bcache.h"
/*
* copied and modified from zonefs_get_dev_capacity() of
* zonefs-tools.
* returns 0: zone size 0 indicates a non-zoned device
* > 0: actual zone size of the zoned device
*/
static size_t get_zone_size(char *devname)
{
char str[128];
FILE *file;
int res;
size_t zone_size = 0;
snprintf(str, sizeof(str),
"/sys/block/%s/queue/chunk_sectors",
basename(devname));
file = fopen(str, "r");
if (!file)
goto out;
memset(str, 0, sizeof(str));
res = fscanf(file, "%s", str);
fclose(file);
if (res != 1)
goto out;
zone_size = atol(str);
out:
return zone_size;
}
/*
* Update data_offset for zoned device, if the backing
* device is a zoned device,
* - just leave whole zone 0 to bcache super block on
* backing device.
* - if data_offset is specified and larger than
* BDEV_DATA_START_DEFAULT, then it should be a zone
* size aligned value.
*/
void check_data_offset_for_zoned_device(char *devname,
uint64_t *data_offset)
{
uint64_t _data_offset = *data_offset;
size_t zone_size = get_zone_size(devname);
if (!zone_size)
return;
if (!_data_offset ||
(_data_offset == BDEV_DATA_START_DEFAULT &&
zone_size > BDEV_DATA_START_DEFAULT))
_data_offset = zone_size;
if (_data_offset < zone_size) {
fprintf(stderr,
"data_offset %lu should be larger than zone_size %lu for zoned device %s\n",
_data_offset, zone_size, devname);
exit(EXIT_FAILURE);
}
if (_data_offset & (zone_size - 1)) {
fprintf(stderr,
"data_offset %lu is not aligned to zone size %lu for zoned device %s\n",
_data_offset, zone_size, devname);
}
*data_offset = _data_offset;
}
int is_zoned_device(char *devname)
{
return (get_zone_size(devname) != 0);
}