LVM2 ソースコードリーディング その1
lvmについての知識を深めるべく、ソースコードリーディング開始
コードはこちら
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/?cvsroot=lvm2
良く使い短めのソースから見てみることにする
構成
まずはディレクトリ構成から
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/?cvsroot=lvm2
toolsフォルダの中身を見れば、良く知っているコマンド名のファイルがたくさんあるのでそれを見ればよさそう
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/tools/?cvsroot=lvm2
pvcreate (LVM2/tools/pvcreate.c)
一番シンプルなpvcreate.cから
関数は2つしかなくていたってシンプル
static int pvcreate_restore_params_validate(struct cmd_context *cmd,
int argc, char **argv,
struct pvcreate_params *pp)
int pvcreate(struct cmd_context *cmd, int argc, char **argv)
そしてpvcreate関数はたったこれだけ
int pvcreate(struct cmd_context *cmd, int argc, char **argv)
{
int i;
int ret = ECMD_PROCESSED;
struct pvcreate_params pp;
struct physical_volume *pv;
pvcreate_params_set_defaults(&pp);
if (!pvcreate_restore_params_validate(cmd, argc, argv, &pp)) {
return EINVALID_CMD_LINE;
}
if (!pvcreate_params_validate(cmd, argc, argv, &pp)) {
return EINVALID_CMD_LINE;
}
for (i = 0; i < argc; i++) {
if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE)) {
log_error("Can't get lock for orphan PVs");
return ECMD_FAILED;
}
dm_unescape_colons_and_at_signs(argv[i], NULL, NULL);
if (!(pv = pvcreate_single(cmd, argv[i], &pp, 1))) {
stack;
ret = ECMD_FAILED;
}
unlock_vg(cmd, VG_ORPHANS);
if (sigint_caught())
return ret;
}
return ret;
}
大体下記の流れ
入力チェック
関数の返り値はこれ
#define ECMD_PROCESSED 1
#define ENO_SUCH_CMD 2
#define EINVALID_CMD_LINE 3
#define ECMD_FAILED 5
※LVM2/lib/commands/errors.h
ロックとか、入力の構造体とかはすっとばして、pv_create_singleを探す。
※LVM2/lib/metadata/metadata.c
/*
* pvcreate_single() - initialize a device with PV label and metadata area
*
* Parameters:
* - pv_name: device path to initialize
* - pp: parameters to pass to pv_create; if NULL, use default values
*
* Returns:
* NULL: error
* struct physical_volume * (non-NULL): handle to physical volume created
*/
struct physical_volume * pvcreate_single(struct cmd_context *cmd,
const char *pv_name,
struct pvcreate_params *pp,
int write_now)
{
struct physical_volume *pv = NULL;
struct device *dev;
struct dm_list mdas;
struct pvcreate_params default_pp;
char buffer[64] __attribute__((aligned(8)));
pvcreate_params_set_defaults(&default_pp);
if (!pp)
pp = &default_pp;
if (pp->idp) {
if ((dev = lvmcache_device_from_pvid(cmd, pp->idp, NULL, NULL)) &&
(dev != dev_cache_get(pv_name, cmd->filter))) {
if (!id_write_format((const struct id*)&pp->idp->uuid,
buffer, sizeof(buffer)))
goto_bad;
log_error("uuid %s already in use on \"%s\"", buffer,
dev_name(dev));
goto bad;;
}
}
if (!pvcreate_check(cmd, pv_name, pp))
goto_bad;
if (sigint_caught())
goto_bad;
if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
log_error("%s: Couldn't find device. Check your filters?",
pv_name);
goto bad;
}
dm_list_init(&mdas);
if (!(pv = pv_create(cmd, dev, pp->idp, pp->size,
pp->data_alignment, pp->data_alignment_offset,
pp->pe_start ? pp->pe_start : PV_PE_START_CALC,
pp->extent_count, pp->extent_size,
pp->labelsector, pp->pvmetadatacopies,
pp->pvmetadatasize, pp->metadataignore))) {
log_error("Failed to setup physical volume \"%s\"", pv_name);
goto bad;
}
log_verbose("Set up physical volume for \"%s\" with %" PRIu64
" available sectors", pv_name, pv_size(pv));
if (write_now) {
struct pv_to_create pvc;
pvc.pp = pp;
pvc.pv = pv;
if (!_pvcreate_write(cmd, &pvc))
goto bad;
} else {
pv->status |= UNLABELLED_PV;
}
return pv;
bad:
return NULL;
}
/**
* pv_create - initialize a physical volume for use with a volume group
* created PV belongs to Orphan VG.
*
* @fmt: format type
* @dev: PV device to initialize
* @size: size of the PV in sectors
* @data_alignment: requested alignment of data
* @data_alignment_offset: requested offset to aligned data
* @pe_start: physical extent start
* @existing_extent_count
* @existing_extent_size
* @pvmetadatacopies
* @pvmetadatasize
* @mdas
*
* Returns:
* PV handle - physical volume initialized successfully
* NULL - invalid parameter or problem initializing the physical volume
*
* Note:
* FIXME: shorten argument list and replace with explict 'set' functions
*/
struct physical_volume *pv_create(const struct cmd_context *cmd,
struct device *dev,
struct id *id, uint64_t size,
unsigned long data_alignment,
unsigned long data_alignment_offset,
uint64_t pe_start,
uint32_t existing_extent_count,
uint32_t existing_extent_size,
uint64_t label_sector,
unsigned pvmetadatacopies,
uint64_t pvmetadatasize,
unsigned metadataignore)
{
const struct format_type *fmt = cmd->fmt;
struct dm_pool *mem = fmt->orphan_vg->vgmem;
struct physical_volume *pv = _alloc_pv(mem, dev);
unsigned mda_index;
struct pv_list *pvl;
if (!pv)
return_NULL;
if (id)
memcpy(&pv->id, id, sizeof(*id));
else if (!id_create(&pv->id)) {
log_error("Failed to create random uuid for %s.",
dev_name(dev));
goto bad;
}
if (!dev_get_size(pv->dev, &pv->size)) {
log_error("%s: Couldn't get size.", pv_dev_name(pv));
goto bad;
}
if (size) {
if (size > pv->size)
log_warn("WARNING: %s: Overriding real size. "
"You could lose data.", pv_dev_name(pv));
log_verbose("%s: Pretending size is %" PRIu64 " sectors.",
pv_dev_name(pv), size);
pv->size = size;
}
if (pv->size < pv_min_size()) {
log_error("%s: Size must exceed minimum of %" PRIu64 " sectors.",
pv_dev_name(pv), pv_min_size());
goto bad;
}
if (pv->size < data_alignment) {
log_error("%s: Data alignment must not exceed device size.",
pv_dev_name(pv));
goto bad;
}
if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl)))) {
log_error("pv_list allocation in pv_create failed");
goto bad;
}
pvl->pv = pv;
add_pvl_to_vgs(fmt->orphan_vg, pvl);
fmt->orphan_vg->extent_count += pv->pe_count;
fmt->orphan_vg->free_count += pv->pe_count;
pv->fmt = fmt;
pv->vg_name = fmt->orphan_vg_name;
if (!fmt->ops->pv_initialise(fmt, label_sector, pe_start,
existing_extent_count, existing_extent_size,
data_alignment, data_alignment_offset, pv)) {
log_error("Format-specific initialisation of physical "
"volume %s failed.", pv_dev_name(pv));
goto bad;
}
for (mda_index = 0; mda_index < pvmetadatacopies; mda_index++) {
if (pv->fmt->ops->pv_add_metadata_area &&
!pv->fmt->ops->pv_add_metadata_area(pv->fmt, pv,
pe_start != PV_PE_START_CALC,
mda_index, pvmetadatasize,
metadataignore)) {
log_error("Failed to add metadata area for "
"new physical volume %s", pv_dev_name(pv));
goto bad;
}
}
return pv;
bad:
// FIXME: detach from orphan in error path
//free_pv_fid(pv);
//dm_pool_free(mem, pv);
return NULL;
}
LVM2/lib/metadata/lv_alloc.h
memo
- Orphan PV is device with PV label which is not attached to any Volume Group.