mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
move code from pvscan.c to online.c
related to managing files in /run/lvm/pvs_online and /run/lvm/vgs_online
This commit is contained in:
parent
2bdc2d4f5e
commit
c310e23b51
@ -40,6 +40,7 @@ SOURCES =\
|
||||
device/dev-luks.c \
|
||||
device/dev-dasd.c \
|
||||
device/dev-lvm1-pool.c \
|
||||
device/online.c \
|
||||
display/display.c \
|
||||
error/errseg.c \
|
||||
unknown/unknown.c \
|
||||
|
@ -202,6 +202,7 @@ struct cmd_context {
|
||||
unsigned ignore_device_name_mismatch:1; /* skip updating devices file names */
|
||||
unsigned backup_disabled:1; /* skip repeated debug message */
|
||||
unsigned event_activation:1; /* whether event_activation is set */
|
||||
unsigned udevoutput:1;
|
||||
|
||||
/*
|
||||
* Devices and filtering.
|
||||
|
306
lib/device/online.c
Normal file
306
lib/device/online.c
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#include "lib/device/device.h"
|
||||
#include "lib/device/device_id.h"
|
||||
#include "lib/device/online.h"
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
static char *_vgname_in_pvid_file_buf(char *buf)
|
||||
{
|
||||
char *p, *n;
|
||||
|
||||
/*
|
||||
* file contains:
|
||||
* <major>:<minor>\n
|
||||
* vg:<vgname>\n\0
|
||||
*/
|
||||
|
||||
if (!(p = strchr(buf, '\n')))
|
||||
return NULL;
|
||||
|
||||
p++; /* skip \n */
|
||||
|
||||
if (*p && !strncmp(p, "vg:", 3)) {
|
||||
if ((n = strchr(p, '\n')))
|
||||
*n = '\0';
|
||||
return p + 3;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define MAX_PVID_FILE_SIZE 512
|
||||
|
||||
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname)
|
||||
{
|
||||
char buf[MAX_PVID_FILE_SIZE] = { 0 };
|
||||
char *name;
|
||||
int fd, rv;
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
log_warn("Failed to open %s", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = read(fd, buf, sizeof(buf) - 1);
|
||||
if (close(fd))
|
||||
log_sys_debug("close", path);
|
||||
if (!rv || rv < 0) {
|
||||
log_warn("No info in %s", path);
|
||||
return 0;
|
||||
}
|
||||
buf[rv] = 0; /* \0 terminated buffer */
|
||||
|
||||
if (sscanf(buf, "%d:%d", major, minor) != 2) {
|
||||
log_warn("No device numbers in %s", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vgname points to an offset in buf */
|
||||
if ((name = _vgname_in_pvid_file_buf(buf)))
|
||||
strncpy(vgname, name, NAME_LEN);
|
||||
else
|
||||
log_debug("No vgname in %s", path);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* When a PV goes offline, remove the vg online file for that VG
|
||||
* (even if other PVs for the VG are still online). This means
|
||||
* that the vg will be activated again when it becomes complete.
|
||||
*/
|
||||
|
||||
void online_vg_file_remove(const char *vgname)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", VGS_ONLINE_DIR, vgname) < 0) {
|
||||
log_error("Path %s/%s is too long.", VGS_ONLINE_DIR, vgname);
|
||||
return;
|
||||
}
|
||||
|
||||
log_debug("Unlink vg online: %s", path);
|
||||
|
||||
if (unlink(path) && (errno != ENOENT))
|
||||
log_sys_debug("unlink", path);
|
||||
}
|
||||
|
||||
int online_vg_file_create(struct cmd_context *cmd, const char *vgname)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
int fd;
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", VGS_ONLINE_DIR, vgname) < 0) {
|
||||
log_error_pvscan(cmd, "Path %s/%s is too long.", VGS_ONLINE_DIR, vgname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("Create vg online: %s", path);
|
||||
|
||||
fd = open(path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
log_debug("Failed to create %s: %d", path, errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We don't care about syncing, these files are not even persistent. */
|
||||
|
||||
if (close(fd))
|
||||
log_sys_debug("close", path);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char buf[MAX_PVID_FILE_SIZE] = { 0 };
|
||||
char file_vgname[NAME_LEN];
|
||||
int file_major = 0, file_minor = 0;
|
||||
int major, minor;
|
||||
int fd;
|
||||
int rv;
|
||||
int len;
|
||||
int len1 = 0;
|
||||
int len2 = 0;
|
||||
|
||||
major = (int)MAJOR(dev->dev);
|
||||
minor = (int)MINOR(dev->dev);
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, dev->pvid) < 0) {
|
||||
log_error_pvscan(cmd, "Path %s/%s is too long.", PVS_ONLINE_DIR, dev->pvid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((len1 = dm_snprintf(buf, sizeof(buf), "%d:%d\n", major, minor)) < 0) {
|
||||
log_error_pvscan(cmd, "Cannot create online file path for %s %d:%d.", dev_name(dev), major, minor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vgname) {
|
||||
if ((len2 = dm_snprintf(buf + len1, sizeof(buf) - len1, "vg:%s\n", vgname)) < 0) {
|
||||
log_print_pvscan(cmd, "Incomplete online file for %s %d:%d vg %s.", dev_name(dev), major, minor, vgname);
|
||||
/* can still continue without vgname */
|
||||
len2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
len = len1 + len2;
|
||||
|
||||
log_debug("Create pv online: %s %d:%d %s", path, major, minor, dev_name(dev));
|
||||
|
||||
fd = open(path, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
if (errno == EEXIST)
|
||||
goto check_duplicate;
|
||||
log_error_pvscan(cmd, "Failed to create online file for %s path %s error %d", dev_name(dev), path, errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
rv = write(fd, buf, len);
|
||||
if (rv < 0) {
|
||||
/* file exists so it still works in part */
|
||||
log_warn("Cannot write online file for %s to %s error %d",
|
||||
dev_name(dev), path, errno);
|
||||
if (close(fd))
|
||||
log_sys_debug("close", path);
|
||||
return 1;
|
||||
}
|
||||
len -= rv;
|
||||
}
|
||||
|
||||
/* We don't care about syncing, these files are not even persistent. */
|
||||
|
||||
if (close(fd))
|
||||
log_sys_debug("close", path);
|
||||
|
||||
return 1;
|
||||
|
||||
check_duplicate:
|
||||
|
||||
/*
|
||||
* If a PVID online file already exists for this PVID, check if the
|
||||
* file contains a different device number, and if so we may have a
|
||||
* duplicate PV.
|
||||
*
|
||||
* FIXME: disable autoactivation of the VG somehow?
|
||||
* The VG may or may not already be activated when a dupicate appears.
|
||||
* Perhaps write a new field in the pv online or vg online file?
|
||||
*/
|
||||
|
||||
memset(file_vgname, 0, sizeof(file_vgname));
|
||||
|
||||
online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
|
||||
|
||||
if ((file_major == major) && (file_minor == minor)) {
|
||||
log_debug("Existing online file for %d:%d", major, minor);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Don't know how vgname might not match, but it's not good so fail. */
|
||||
|
||||
if ((file_major != major) || (file_minor != minor))
|
||||
log_error_pvscan(cmd, "PV %s is duplicate for PVID %s on %d:%d and %d:%d.",
|
||||
dev_name(dev), dev->pvid, major, minor, file_major, file_minor);
|
||||
|
||||
if (file_vgname[0] && vgname && strcmp(file_vgname, vgname))
|
||||
log_error_pvscan(cmd, "PV %s has unexpected VG %s vs %s.",
|
||||
dev_name(dev), vgname, file_vgname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int online_pvid_file_exists(const char *pvid)
|
||||
{
|
||||
char path[PATH_MAX] = { 0 };
|
||||
struct stat buf;
|
||||
int rv;
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, pvid) < 0) {
|
||||
log_debug(INTERNAL_ERROR "Path %s/%s is too long.", PVS_ONLINE_DIR, pvid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("Check pv online: %s", path);
|
||||
|
||||
rv = stat(path, &buf);
|
||||
if (!rv) {
|
||||
log_debug("Check pv online %s: yes", pvid);
|
||||
return 1;
|
||||
}
|
||||
log_debug("Check pv online %s: no", pvid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void online_dir_setup(struct cmd_context *cmd)
|
||||
{
|
||||
struct stat st;
|
||||
int rv;
|
||||
|
||||
if (!stat(DEFAULT_RUN_DIR, &st))
|
||||
goto do_pvs;
|
||||
|
||||
log_debug("Creating run_dir.");
|
||||
dm_prepare_selinux_context(DEFAULT_RUN_DIR, S_IFDIR);
|
||||
rv = mkdir(DEFAULT_RUN_DIR, 0755);
|
||||
dm_prepare_selinux_context(NULL, 0);
|
||||
|
||||
if ((rv < 0) && stat(DEFAULT_RUN_DIR, &st))
|
||||
log_error_pvscan(cmd, "Failed to create %s %d", DEFAULT_RUN_DIR, errno);
|
||||
|
||||
do_pvs:
|
||||
if (!stat(PVS_ONLINE_DIR, &st))
|
||||
goto do_vgs;
|
||||
|
||||
log_debug("Creating pvs_online_dir.");
|
||||
dm_prepare_selinux_context(PVS_ONLINE_DIR, S_IFDIR);
|
||||
rv = mkdir(PVS_ONLINE_DIR, 0755);
|
||||
dm_prepare_selinux_context(NULL, 0);
|
||||
|
||||
if ((rv < 0) && stat(PVS_ONLINE_DIR, &st))
|
||||
log_error_pvscan(cmd, "Failed to create %s %d", PVS_ONLINE_DIR, errno);
|
||||
|
||||
do_vgs:
|
||||
if (!stat(VGS_ONLINE_DIR, &st))
|
||||
goto do_lookup;
|
||||
|
||||
log_debug("Creating vgs_online_dir.");
|
||||
dm_prepare_selinux_context(VGS_ONLINE_DIR, S_IFDIR);
|
||||
rv = mkdir(VGS_ONLINE_DIR, 0755);
|
||||
dm_prepare_selinux_context(NULL, 0);
|
||||
|
||||
if ((rv < 0) && stat(VGS_ONLINE_DIR, &st))
|
||||
log_error_pvscan(cmd, "Failed to create %s %d", VGS_ONLINE_DIR, errno);
|
||||
|
||||
do_lookup:
|
||||
if (!stat(PVS_LOOKUP_DIR, &st))
|
||||
return;
|
||||
|
||||
log_debug("Creating pvs_lookup_dir.");
|
||||
dm_prepare_selinux_context(PVS_LOOKUP_DIR, S_IFDIR);
|
||||
rv = mkdir(PVS_LOOKUP_DIR, 0755);
|
||||
dm_prepare_selinux_context(NULL, 0);
|
||||
|
||||
if ((rv < 0) && stat(PVS_LOOKUP_DIR, &st))
|
||||
log_error_pvscan(cmd, "Failed to create %s %d", PVS_LOOKUP_DIR, errno);
|
||||
|
||||
|
||||
}
|
46
lib/device/online.h
Normal file
46
lib/device/online.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _ONLINE_H
|
||||
#define _ONLINE_H
|
||||
|
||||
/*
|
||||
* Avoid a duplicate pvscan[%d] prefix when logging to the journal.
|
||||
* FIXME: this should probably replace if (udevoutput) with
|
||||
* if (log_journal & LOG_JOURNAL_OUTPUT)
|
||||
*/
|
||||
#define log_print_pvscan(cmd, fmt, args...) \
|
||||
do \
|
||||
if (cmd->udevoutput) \
|
||||
log_print(fmt, ##args); \
|
||||
else \
|
||||
log_print("pvscan[%d] " fmt, getpid(), ##args); \
|
||||
while (0)
|
||||
|
||||
#define log_error_pvscan(cmd, fmt, args...) \
|
||||
do \
|
||||
if (cmd->udevoutput) \
|
||||
log_error(fmt, ##args); \
|
||||
else \
|
||||
log_error("pvscan[%d] " fmt, getpid(), ##args); \
|
||||
while (0)
|
||||
|
||||
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname);
|
||||
int online_vg_file_create(struct cmd_context *cmd, const char *vgname);
|
||||
void online_vg_file_remove(const char *vgname);
|
||||
int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname);
|
||||
int online_pvid_file_exists(const char *pvid);
|
||||
void online_dir_setup(struct cmd_context *cmd);
|
||||
|
||||
#endif
|
@ -146,6 +146,7 @@
|
||||
#include "lib/label/hints.h"
|
||||
#include "lib/device/dev-type.h"
|
||||
#include "lib/device/device_id.h"
|
||||
#include "lib/device/online.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
@ -156,8 +157,6 @@
|
||||
#include <sys/file.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname);
|
||||
|
||||
static const char *_hints_file = DEFAULT_RUN_DIR "/hints";
|
||||
static const char *_nohints_file = DEFAULT_RUN_DIR "/nohints";
|
||||
static const char *_newhints_file = DEFAULT_RUN_DIR "/newhints";
|
||||
|
@ -2393,8 +2393,10 @@ static void _reset_current_settings_to_default(struct cmd_context *cmd)
|
||||
|
||||
static void _get_current_output_settings_from_args(struct cmd_context *cmd)
|
||||
{
|
||||
if (arg_is_set(cmd, udevoutput_ARG))
|
||||
if (arg_is_set(cmd, udevoutput_ARG)) {
|
||||
cmd->current_settings.suppress = 1;
|
||||
cmd->udevoutput = 1;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, debug_ARG))
|
||||
cmd->current_settings.debug = _LOG_FATAL + (arg_count(cmd, debug_ARG) - 1);
|
||||
|
360
tools/pvscan.c
360
tools/pvscan.c
@ -18,11 +18,10 @@
|
||||
#include "lib/cache/lvmcache.h"
|
||||
#include "lib/metadata/metadata.h"
|
||||
#include "lib/label/hints.h"
|
||||
#include "lib/device/online.h"
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname);
|
||||
|
||||
struct pvscan_params {
|
||||
int new_pvs_found;
|
||||
int pvs_found;
|
||||
@ -44,10 +43,6 @@ struct pvscan_aa_params {
|
||||
*/
|
||||
static struct volume_group *saved_vg;
|
||||
|
||||
static const char *_pvs_online_dir = DEFAULT_RUN_DIR "/pvs_online";
|
||||
static const char *_vgs_online_dir = DEFAULT_RUN_DIR "/vgs_online";
|
||||
static const char *_pvs_lookup_dir = DEFAULT_RUN_DIR "/pvs_lookup";
|
||||
|
||||
static int _pvscan_display_pv(struct cmd_context *cmd,
|
||||
struct physical_volume *pv,
|
||||
struct pvscan_params *params)
|
||||
@ -181,93 +176,12 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Avoid a duplicate pvscan[%d] prefix when logging to the journal.
|
||||
* FIXME: this should probably replace if (udevoutput) with
|
||||
* if (log_journal & LOG_JOURNAL_OUTPUT)
|
||||
*/
|
||||
#define log_print_pvscan(cmd, fmt, args...) \
|
||||
do \
|
||||
if (arg_is_set(cmd, udevoutput_ARG)) \
|
||||
log_print(fmt, ##args); \
|
||||
else \
|
||||
log_print("pvscan[%d] " fmt, getpid(), ##args); \
|
||||
while (0)
|
||||
|
||||
#define log_error_pvscan(cmd, fmt, args...) \
|
||||
do \
|
||||
if (arg_is_set(cmd, udevoutput_ARG)) \
|
||||
log_error(fmt, ##args); \
|
||||
else \
|
||||
log_error("pvscan[%d] " fmt, getpid(), ##args); \
|
||||
while (0)
|
||||
|
||||
static char *_vgname_in_pvid_file_buf(char *buf)
|
||||
{
|
||||
char *p, *n;
|
||||
|
||||
/*
|
||||
* file contains:
|
||||
* <major>:<minor>\n
|
||||
* vg:<vgname>\n\0
|
||||
*/
|
||||
|
||||
if (!(p = strchr(buf, '\n')))
|
||||
return NULL;
|
||||
|
||||
p++; /* skip \n */
|
||||
|
||||
if (*p && !strncmp(p, "vg:", 3)) {
|
||||
if ((n = strchr(p, '\n')))
|
||||
*n = '\0';
|
||||
return p + 3;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define MAX_PVID_FILE_SIZE 512
|
||||
|
||||
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname)
|
||||
{
|
||||
char buf[MAX_PVID_FILE_SIZE] = { 0 };
|
||||
char *name;
|
||||
int fd, rv;
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
log_warn("Failed to open %s", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = read(fd, buf, sizeof(buf) - 1);
|
||||
if (close(fd))
|
||||
log_sys_debug("close", path);
|
||||
if (!rv || rv < 0) {
|
||||
log_warn("No info in %s", path);
|
||||
return 0;
|
||||
}
|
||||
buf[rv] = 0; /* \0 terminated buffer */
|
||||
|
||||
if (sscanf(buf, "%d:%d", major, minor) != 2) {
|
||||
log_warn("No device numbers in %s", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vgname points to an offset in buf */
|
||||
if ((name = _vgname_in_pvid_file_buf(buf)))
|
||||
strncpy(vgname, name, NAME_LEN);
|
||||
else
|
||||
log_debug("No vgname in %s", path);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _lookup_file_remove(char *vgname)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_lookup_dir, vgname) < 0) {
|
||||
log_error("Path %s/%s is too long.", _pvs_lookup_dir, vgname);
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_LOOKUP_DIR, vgname) < 0) {
|
||||
log_error("Path %s/%s is too long.", PVS_LOOKUP_DIR, vgname);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -277,27 +191,6 @@ static void _lookup_file_remove(char *vgname)
|
||||
log_sys_debug("unlink", path);
|
||||
}
|
||||
|
||||
/*
|
||||
* When a PV goes offline, remove the vg online file for that VG
|
||||
* (even if other PVs for the VG are still online). This means
|
||||
* that the vg will be activated again when it becomes complete.
|
||||
*/
|
||||
|
||||
void online_vg_file_remove(const char *vgname)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", _vgs_online_dir, vgname) < 0) {
|
||||
log_error("Path %s/%s is too long.", _vgs_online_dir, vgname);
|
||||
return;
|
||||
}
|
||||
|
||||
log_debug("Unlink vg online: %s", path);
|
||||
|
||||
if (unlink(path) && (errno != ENOENT))
|
||||
log_sys_debug("unlink", path);
|
||||
}
|
||||
|
||||
/*
|
||||
* When a device goes offline we only know its major:minor, not its PVID.
|
||||
* Since the dev isn't around, we can't read it to get its PVID, so we have to
|
||||
@ -316,7 +209,7 @@ static void _online_pvid_file_remove_devno(int major, int minor)
|
||||
|
||||
log_debug("Remove pv online devno %d:%d", major, minor);
|
||||
|
||||
if (!(dir = opendir(_pvs_online_dir)))
|
||||
if (!(dir = opendir(PVS_ONLINE_DIR)))
|
||||
return;
|
||||
|
||||
while ((de = readdir(dir))) {
|
||||
@ -324,7 +217,7 @@ static void _online_pvid_file_remove_devno(int major, int minor)
|
||||
continue;
|
||||
|
||||
memset(path, 0, sizeof(path));
|
||||
snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, de->d_name);
|
||||
snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, de->d_name);
|
||||
|
||||
file_major = 0;
|
||||
file_minor = 0;
|
||||
@ -344,7 +237,7 @@ static void _online_pvid_file_remove_devno(int major, int minor)
|
||||
}
|
||||
}
|
||||
if (closedir(dir))
|
||||
log_sys_debug("closedir", _pvs_online_dir);
|
||||
log_sys_debug("closedir", PVS_ONLINE_DIR);
|
||||
}
|
||||
|
||||
static void _online_files_remove(const char *dirpath)
|
||||
@ -369,128 +262,6 @@ static void _online_files_remove(const char *dirpath)
|
||||
log_sys_debug("closedir", dirpath);
|
||||
}
|
||||
|
||||
static int _online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char buf[MAX_PVID_FILE_SIZE] = { 0 };
|
||||
char file_vgname[NAME_LEN];
|
||||
int file_major = 0, file_minor = 0;
|
||||
int major, minor;
|
||||
int fd;
|
||||
int rv;
|
||||
int len;
|
||||
int len1 = 0;
|
||||
int len2 = 0;
|
||||
|
||||
major = (int)MAJOR(dev->dev);
|
||||
minor = (int)MINOR(dev->dev);
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, dev->pvid) < 0) {
|
||||
log_error_pvscan(cmd, "Path %s/%s is too long.", _pvs_online_dir, dev->pvid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((len1 = dm_snprintf(buf, sizeof(buf), "%d:%d\n", major, minor)) < 0) {
|
||||
log_error_pvscan(cmd, "Cannot create online file path for %s %d:%d.", dev_name(dev), major, minor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vgname) {
|
||||
if ((len2 = dm_snprintf(buf + len1, sizeof(buf) - len1, "vg:%s\n", vgname)) < 0) {
|
||||
log_print_pvscan(cmd, "Incomplete online file for %s %d:%d vg %s.", dev_name(dev), major, minor, vgname);
|
||||
/* can still continue without vgname */
|
||||
len2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
len = len1 + len2;
|
||||
|
||||
log_debug("Create pv online: %s %d:%d %s", path, major, minor, dev_name(dev));
|
||||
|
||||
fd = open(path, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
if (errno == EEXIST)
|
||||
goto check_duplicate;
|
||||
log_error_pvscan(cmd, "Failed to create online file for %s path %s error %d", dev_name(dev), path, errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
rv = write(fd, buf, len);
|
||||
if (rv < 0) {
|
||||
/* file exists so it still works in part */
|
||||
log_warn("Cannot write online file for %s to %s error %d",
|
||||
dev_name(dev), path, errno);
|
||||
if (close(fd))
|
||||
log_sys_debug("close", path);
|
||||
return 1;
|
||||
}
|
||||
len -= rv;
|
||||
}
|
||||
|
||||
/* We don't care about syncing, these files are not even persistent. */
|
||||
|
||||
if (close(fd))
|
||||
log_sys_debug("close", path);
|
||||
|
||||
return 1;
|
||||
|
||||
check_duplicate:
|
||||
|
||||
/*
|
||||
* If a PVID online file already exists for this PVID, check if the
|
||||
* file contains a different device number, and if so we may have a
|
||||
* duplicate PV.
|
||||
*
|
||||
* FIXME: disable autoactivation of the VG somehow?
|
||||
* The VG may or may not already be activated when a dupicate appears.
|
||||
* Perhaps write a new field in the pv online or vg online file?
|
||||
*/
|
||||
|
||||
memset(file_vgname, 0, sizeof(file_vgname));
|
||||
|
||||
online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
|
||||
|
||||
if ((file_major == major) && (file_minor == minor)) {
|
||||
log_debug("Existing online file for %d:%d", major, minor);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Don't know how vgname might not match, but it's not good so fail. */
|
||||
|
||||
if ((file_major != major) || (file_minor != minor))
|
||||
log_error_pvscan(cmd, "PV %s is duplicate for PVID %s on %d:%d and %d:%d.",
|
||||
dev_name(dev), dev->pvid, major, minor, file_major, file_minor);
|
||||
|
||||
if (file_vgname[0] && vgname && strcmp(file_vgname, vgname))
|
||||
log_error_pvscan(cmd, "PV %s has unexpected VG %s vs %s.",
|
||||
dev_name(dev), vgname, file_vgname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _online_pvid_file_exists(const char *pvid)
|
||||
{
|
||||
char path[PATH_MAX] = { 0 };
|
||||
struct stat buf;
|
||||
int rv;
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, pvid) < 0) {
|
||||
log_debug(INTERNAL_ERROR "Path %s/%s is too long.", _pvs_online_dir, pvid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("Check pv online: %s", path);
|
||||
|
||||
rv = stat(path, &buf);
|
||||
if (!rv) {
|
||||
log_debug("Check pv online %s: yes", pvid);
|
||||
return 1;
|
||||
}
|
||||
log_debug("Check pv online %s: no", pvid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _write_lookup_file(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
@ -498,8 +269,8 @@ static int _write_lookup_file(struct cmd_context *cmd, struct volume_group *vg)
|
||||
struct pv_list *pvl;
|
||||
int fd;
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_lookup_dir, vg->name) < 0) {
|
||||
log_error_pvscan(cmd, "Path %s/%s is too long.", _pvs_lookup_dir, vg->name);
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_LOOKUP_DIR, vg->name) < 0) {
|
||||
log_error_pvscan(cmd, "Path %s/%s is too long.", PVS_LOOKUP_DIR, vg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -555,7 +326,7 @@ static void _lookup_file_count_pvid_files(FILE *fp, const char *vgname, int *pvs
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_online_pvid_file_exists((const char *)pvid))
|
||||
if (online_pvid_file_exists((const char *)pvid))
|
||||
(*pvs_online)++;
|
||||
else
|
||||
(*pvs_offline)++;
|
||||
@ -616,8 +387,8 @@ static int _count_pvid_files_from_lookup_file(struct cmd_context *cmd, struct de
|
||||
*pvs_online = 0;
|
||||
*pvs_offline = 0;
|
||||
|
||||
if (!(dir = opendir(_pvs_lookup_dir))) {
|
||||
log_sys_debug("opendir", _pvs_lookup_dir);
|
||||
if (!(dir = opendir(PVS_LOOKUP_DIR))) {
|
||||
log_sys_debug("opendir", PVS_LOOKUP_DIR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -629,8 +400,8 @@ static int _count_pvid_files_from_lookup_file(struct cmd_context *cmd, struct de
|
||||
if (de->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_lookup_dir, de->d_name) < 0) {
|
||||
log_warn("WARNING: Path %s/%s is too long.", _pvs_lookup_dir, de->d_name);
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_LOOKUP_DIR, de->d_name) < 0) {
|
||||
log_warn("WARNING: Path %s/%s is too long.", PVS_LOOKUP_DIR, de->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -655,68 +426,13 @@ static int _count_pvid_files_from_lookup_file(struct cmd_context *cmd, struct de
|
||||
log_sys_debug("fclose", path);
|
||||
}
|
||||
if (closedir(dir))
|
||||
log_sys_debug("closedir", _pvs_lookup_dir);
|
||||
log_sys_debug("closedir", PVS_LOOKUP_DIR);
|
||||
|
||||
*vgname_out = vgname;
|
||||
|
||||
return (vgname) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void _online_dir_setup(struct cmd_context *cmd)
|
||||
{
|
||||
struct stat st;
|
||||
int rv;
|
||||
|
||||
if (!stat(DEFAULT_RUN_DIR, &st))
|
||||
goto do_pvs;
|
||||
|
||||
log_debug("Creating run_dir.");
|
||||
dm_prepare_selinux_context(DEFAULT_RUN_DIR, S_IFDIR);
|
||||
rv = mkdir(DEFAULT_RUN_DIR, 0755);
|
||||
dm_prepare_selinux_context(NULL, 0);
|
||||
|
||||
if ((rv < 0) && stat(DEFAULT_RUN_DIR, &st))
|
||||
log_error_pvscan(cmd, "Failed to create %s %d", DEFAULT_RUN_DIR, errno);
|
||||
|
||||
do_pvs:
|
||||
if (!stat(_pvs_online_dir, &st))
|
||||
goto do_vgs;
|
||||
|
||||
log_debug("Creating pvs_online_dir.");
|
||||
dm_prepare_selinux_context(_pvs_online_dir, S_IFDIR);
|
||||
rv = mkdir(_pvs_online_dir, 0755);
|
||||
dm_prepare_selinux_context(NULL, 0);
|
||||
|
||||
if ((rv < 0) && stat(_pvs_online_dir, &st))
|
||||
log_error_pvscan(cmd, "Failed to create %s %d", _pvs_online_dir, errno);
|
||||
|
||||
do_vgs:
|
||||
if (!stat(_vgs_online_dir, &st))
|
||||
goto do_lookup;
|
||||
|
||||
log_debug("Creating vgs_online_dir.");
|
||||
dm_prepare_selinux_context(_vgs_online_dir, S_IFDIR);
|
||||
rv = mkdir(_vgs_online_dir, 0755);
|
||||
dm_prepare_selinux_context(NULL, 0);
|
||||
|
||||
if ((rv < 0) && stat(_vgs_online_dir, &st))
|
||||
log_error_pvscan(cmd, "Failed to create %s %d", _vgs_online_dir, errno);
|
||||
|
||||
do_lookup:
|
||||
if (!stat(_pvs_lookup_dir, &st))
|
||||
return;
|
||||
|
||||
log_debug("Creating pvs_lookup_dir.");
|
||||
dm_prepare_selinux_context(_pvs_lookup_dir, S_IFDIR);
|
||||
rv = mkdir(_pvs_lookup_dir, 0755);
|
||||
dm_prepare_selinux_context(NULL, 0);
|
||||
|
||||
if ((rv < 0) && stat(_pvs_lookup_dir, &st))
|
||||
log_error_pvscan(cmd, "Failed to create %s %d", _pvs_lookup_dir, errno);
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void _count_pvid_files(struct volume_group *vg, int *pvs_online, int *pvs_offline)
|
||||
{
|
||||
char pvid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
|
||||
@ -727,7 +443,7 @@ static void _count_pvid_files(struct volume_group *vg, int *pvs_online, int *pvs
|
||||
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
memcpy(pvid, &pvl->pv->id.uuid, ID_LEN);
|
||||
if (_online_pvid_file_exists(pvid))
|
||||
if (online_pvid_file_exists(pvid))
|
||||
(*pvs_online)++;
|
||||
else
|
||||
(*pvs_offline)++;
|
||||
@ -758,32 +474,6 @@ static int _pvscan_aa_single(struct cmd_context *cmd, const char *vg_name,
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
static int _online_vg_file_create(struct cmd_context *cmd, const char *vgname)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
int fd;
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", _vgs_online_dir, vgname) < 0) {
|
||||
log_error_pvscan(cmd, "Path %s/%s is too long.", _vgs_online_dir, vgname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("Create vg online: %s", path);
|
||||
|
||||
fd = open(path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
log_debug("Failed to create %s: %d", path, errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We don't care about syncing, these files are not even persistent. */
|
||||
|
||||
if (close(fd))
|
||||
log_sys_debug("close", path);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a very unconventional way of doing things because
|
||||
* we want to figure out which devices to read the VG from
|
||||
@ -843,7 +533,7 @@ static int _get_devs_from_saved_vg(struct cmd_context *cmd, const char *vgname,
|
||||
memcpy(pvid, &pvl->pv->id.uuid, ID_LEN);
|
||||
|
||||
memset(path, 0, sizeof(path));
|
||||
snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, pvid);
|
||||
snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, pvid);
|
||||
|
||||
file_major = 0;
|
||||
file_minor = 0;
|
||||
@ -1072,7 +762,7 @@ static int _pvscan_aa(struct cmd_context *cmd, struct pvscan_aa_params *pp,
|
||||
* to run the activation. The first to create the file will do it.
|
||||
*/
|
||||
dm_list_iterate_items_safe(sl, sl2, vgnames) {
|
||||
if (!_online_vg_file_create(cmd, sl->str)) {
|
||||
if (!online_vg_file_create(cmd, sl->str)) {
|
||||
log_print_pvscan(cmd, "VG %s skip autoactivation.", sl->str);
|
||||
str_list_del(vgnames, sl->str);
|
||||
continue;
|
||||
@ -1242,7 +932,7 @@ static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_online_pvid_file_exists(pvid)) {
|
||||
if (!online_pvid_file_exists(pvid)) {
|
||||
log_debug("set_pv_devices_online vg %s pv %s no online file",
|
||||
vg->name, pvid);
|
||||
pvl->pv->status |= MISSING_PV;
|
||||
@ -1250,7 +940,7 @@ static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group
|
||||
}
|
||||
|
||||
memset(path, 0, sizeof(path));
|
||||
snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, pvid);
|
||||
snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, pvid);
|
||||
|
||||
major = 0;
|
||||
minor = 0;
|
||||
@ -1422,7 +1112,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
|
||||
* Create file named for pvid to record this PV is online.
|
||||
* The command creates/checks online files only when --cache is used.
|
||||
*/
|
||||
if (do_cache && !_online_pvid_file_create(cmd, dev, vg ? vg->name : NULL)) {
|
||||
if (do_cache && !online_pvid_file_create(cmd, dev, vg ? vg->name : NULL)) {
|
||||
log_error_pvscan(cmd, "PV %s failed to create online file.", dev_name(dev));
|
||||
release_vg(vg);
|
||||
ret = 0;
|
||||
@ -1507,7 +1197,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
|
||||
} else if (!do_check_complete) {
|
||||
log_print("VG %s", vgname);
|
||||
} else if (vg_complete) {
|
||||
if (do_vgonline && !_online_vg_file_create(cmd, vgname)) {
|
||||
if (do_vgonline && !online_vg_file_create(cmd, vgname)) {
|
||||
log_print("VG %s finished", vgname);
|
||||
} else {
|
||||
/*
|
||||
@ -1613,9 +1303,9 @@ static int _pvscan_cache_all(struct cmd_context *cmd, int argc, char **argv,
|
||||
|
||||
dm_list_init(&pvscan_devs);
|
||||
|
||||
_online_files_remove(_pvs_online_dir);
|
||||
_online_files_remove(_vgs_online_dir);
|
||||
_online_files_remove(_pvs_lookup_dir);
|
||||
_online_files_remove(PVS_ONLINE_DIR);
|
||||
_online_files_remove(VGS_ONLINE_DIR);
|
||||
_online_files_remove(PVS_LOOKUP_DIR);
|
||||
|
||||
unlink_searched_devnames(cmd);
|
||||
|
||||
@ -1958,7 +1648,7 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
do_all = !argc && !devno_args;
|
||||
|
||||
_online_dir_setup(cmd);
|
||||
online_dir_setup(cmd);
|
||||
|
||||
if (do_all) {
|
||||
if (!_pvscan_cache_all(cmd, argc, argv, &complete_vgnames))
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "lib/format_text/format-text.h"
|
||||
#include "lib/label/hints.h"
|
||||
#include "lib/device/device_id.h"
|
||||
#include "lib/device/online.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
|
@ -295,6 +295,4 @@ int lvconvert_cachevol_attach_single(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct processing_handle *handle);
|
||||
|
||||
void online_vg_file_remove(const char *vgname);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user