mirror of
git://sourceware.org/git/lvm2.git
synced 2025-12-29 06:57:46 +03:00
Compare commits
16 Commits
dm_v1_02_2
...
dm_v1_02_2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
897fc59f72 | ||
|
|
947e44ae67 | ||
|
|
e44843beba | ||
|
|
147482ea69 | ||
|
|
09091c5cf8 | ||
|
|
50827a5f69 | ||
|
|
2d6444c924 | ||
|
|
1d2675d9aa | ||
|
|
ad98990a8e | ||
|
|
8e58c143f2 | ||
|
|
556a4a2395 | ||
|
|
5be987b40f | ||
|
|
066bc35e69 | ||
|
|
403779437c | ||
|
|
fb806f61d4 | ||
|
|
6ce306661c |
19
WHATS_NEW
19
WHATS_NEW
@@ -1,5 +1,12 @@
|
||||
Version 2.02.29 -
|
||||
==================================
|
||||
Version 2.02.30 -
|
||||
===================================
|
||||
Replace tools/fsadm with scripts/fsadm.sh.
|
||||
Append fields to report/pvsegs_cols_verbose.
|
||||
Permit LV segment fields with PV segment reports.
|
||||
Add seg_start_pe and seg_pe_ranges to reports.
|
||||
|
||||
Version 2.02.29 - 5th December 2007
|
||||
===================================
|
||||
Make clvmd backup vg metadata on remote nodes.
|
||||
Refactor pvmove allocation code.
|
||||
Decode cluster locking state in log message.
|
||||
@@ -36,14 +43,16 @@ Version 2.02.29 -
|
||||
Add const attributes to pv accessor functions.
|
||||
Refactor vg_add_snapshot() and lv_create_empty().
|
||||
Handle new sysfs subsystem/block/devices directory structure.
|
||||
Tests are run with LVM_SYSTEM_DIR pointing to private root and /dev dirs.
|
||||
Run test with LVM_SYSTEM_DIR pointing to private root and /dev dirs.
|
||||
Fix a bug in lvm_dump.sh checks for lvm/dmsetup binaries.
|
||||
Fix underquotations in lvm_dump.sh.
|
||||
Refactor lvcreate stripe and mirror parameter validation.
|
||||
All tools: print --help output to stdout, not stderr.
|
||||
After a diagnostic, suggest --help, rather than printing all --help output.
|
||||
Print --help output to stdout, not stderr.
|
||||
After a cmdline processing error, don't print help text but suggest --help.
|
||||
Add %PVS extents option to lvresize, lvextend, and lvcreate.
|
||||
Add 'make check' to run tests in new subdirectory 'test'.
|
||||
Moved the obsolete test subdirectory to old-tests.
|
||||
Cope with relative paths in configure --with-dmdir.
|
||||
Remove no-longer-correct restrictions on PV arg count with stripes/mirrors.
|
||||
Fix strdup memory leak in str_list_dup().
|
||||
Link with -lpthread when static SELinux libraries require that.
|
||||
|
||||
10
WHATS_NEW_DM
10
WHATS_NEW_DM
@@ -1,10 +1,18 @@
|
||||
Version 1.02.24 - 20th December 2007
|
||||
====================================
|
||||
Fix deptree to pass new name to _resume_node after a rename.
|
||||
Suppress other node operations if node is deleted.
|
||||
Add node operation stack debug messages.
|
||||
Report error when empty device name passed to readahead functions.
|
||||
Fix minimum readahead debug message.
|
||||
|
||||
Version 1.02.23 - 5th December 2007
|
||||
===================================
|
||||
Update dm-ioctl.h after removal of compat code.
|
||||
Add readahead support to libdevmapper and dmsetup.
|
||||
Fix double free in a libdevmapper-event error path.
|
||||
Fix configure --with-dmeventd-path substitution.
|
||||
Allow a DM_DEV_DIR environment variable to override /dev.
|
||||
Allow a DM_DEV_DIR environment variable to override /dev in dmsetup.
|
||||
Create a libdevmapper.so.$LIB_VERSION symlink within the build tree.
|
||||
Avoid static link failure with some SELinux libraries that require libpthread.
|
||||
Remove obsolete dmfs code from tree and update INSTALL.
|
||||
|
||||
10
configure.in
10
configure.in
@@ -1,6 +1,6 @@
|
||||
##
|
||||
## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved.
|
||||
## Copyright (C) 2004, 2007 Red Hat, Inc. All rights reserved.
|
||||
## Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
|
||||
##
|
||||
## This file is part of LVM2.
|
||||
##
|
||||
@@ -363,7 +363,7 @@ AC_MSG_RESULT($CMDLIB)
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable fsadm
|
||||
AC_MSG_CHECKING(whether to build fsadm)
|
||||
AC_MSG_CHECKING(whether to install fsadm)
|
||||
AC_ARG_ENABLE(fsadm, [ --enable-fsadm Enable fsadm],
|
||||
FSADM=$enableval)
|
||||
AC_MSG_RESULT($FSADM)
|
||||
@@ -558,11 +558,6 @@ if test x$CLVMD != xnone; then
|
||||
AC_FUNC_SELECT_ARGTYPES
|
||||
fi
|
||||
|
||||
if test x$FSADM = xyes; then
|
||||
AC_CHECK_HEADERS(fstab.h sys/mount.h sys/vfs.h,,AC_MSG_ERROR(bailing out))
|
||||
AC_CHECK_FUNCS(memmove,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
|
||||
if test x$CLUSTER != xnone; then
|
||||
AC_CHECK_HEADERS(sys/socket.h sys/un.h,,AC_MSG_ERROR(bailing out))
|
||||
AC_CHECK_FUNCS(socket,,AC_MSG_ERROR(bailing out))
|
||||
@@ -661,7 +656,6 @@ po/Makefile
|
||||
scripts/Makefile
|
||||
tools/Makefile
|
||||
tools/version.h
|
||||
tools/fsadm/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
|
||||
@@ -952,10 +952,10 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
max_stripe_size = seg->stripe_size;
|
||||
}
|
||||
|
||||
if (read_ahead == DM_READ_AHEAD_AUTO)
|
||||
if (read_ahead == DM_READ_AHEAD_AUTO) {
|
||||
read_ahead = max_stripe_size;
|
||||
else
|
||||
read_ahead_flags = DM_READ_AHEAD_MINIMUM_FLAG;
|
||||
}
|
||||
|
||||
dm_tree_node_set_read_ahead(dnode, read_ahead, read_ahead_flags);
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
#define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid"
|
||||
#define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid"
|
||||
#define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"
|
||||
#define DEFAULT_PVSEGS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
|
||||
#define DEFAULT_PVSEGS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size,lv_name,seg_start_pe,segtype,seg_pe_ranges"
|
||||
|
||||
#define DEFAULT_LVS_SORT "vg_name,lv_name"
|
||||
#define DEFAULT_VGS_SORT "vg_name"
|
||||
|
||||
@@ -50,6 +50,7 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
|
||||
uint32_t extents,
|
||||
struct list *allocatable_pvs,
|
||||
alloc_policy_t alloc,
|
||||
unsigned can_split,
|
||||
struct list *parallel_areas);
|
||||
|
||||
int lv_add_segment(struct alloc_handle *ah,
|
||||
|
||||
@@ -1055,13 +1055,13 @@ static int _allocate(struct alloc_handle *ah,
|
||||
struct volume_group *vg,
|
||||
struct logical_volume *lv,
|
||||
uint32_t new_extents,
|
||||
unsigned can_split,
|
||||
struct list *allocatable_pvs)
|
||||
{
|
||||
struct pv_area **areas;
|
||||
uint32_t allocated = lv ? lv->le_count : 0;
|
||||
uint32_t old_allocated;
|
||||
struct lv_segment *prev_lvseg = NULL;
|
||||
unsigned can_split = 1; /* Are we allowed more than one segment? */
|
||||
int r = 0;
|
||||
struct list *pvms;
|
||||
uint32_t areas_size;
|
||||
@@ -1180,6 +1180,7 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
|
||||
uint32_t extents,
|
||||
struct list *allocatable_pvs,
|
||||
alloc_policy_t alloc,
|
||||
unsigned can_split,
|
||||
struct list *parallel_areas)
|
||||
{
|
||||
struct alloc_handle *ah;
|
||||
@@ -1208,7 +1209,7 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
|
||||
|
||||
if (!segtype_is_virtual(segtype) &&
|
||||
!_allocate(ah, vg, lv, (lv ? lv->le_count : 0) + extents,
|
||||
allocatable_pvs)) {
|
||||
can_split, allocatable_pvs)) {
|
||||
stack;
|
||||
alloc_destroy(ah);
|
||||
return NULL;
|
||||
@@ -1403,16 +1404,18 @@ int lv_extend(struct logical_volume *lv,
|
||||
uint32_t m;
|
||||
struct alloc_handle *ah;
|
||||
struct lv_segment *seg;
|
||||
unsigned can_split = 1;
|
||||
|
||||
if (segtype_is_virtual(segtype))
|
||||
return lv_add_virtual_segment(lv, status, extents, segtype);
|
||||
|
||||
/* FIXME Temporary restriction during code reorganisation */
|
||||
if (mirrored_pv)
|
||||
alloc = ALLOC_CONTIGUOUS;
|
||||
can_split = 0;
|
||||
|
||||
if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors, 0,
|
||||
extents, allocatable_pvs, alloc, NULL)))
|
||||
extents, allocatable_pvs, alloc, can_split,
|
||||
NULL)))
|
||||
return_0;
|
||||
|
||||
if (mirrors < 2) {
|
||||
|
||||
@@ -55,9 +55,6 @@
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#undef HAVE_FORK
|
||||
|
||||
/* Define to 1 if you have the <fstab.h> header file. */
|
||||
#undef HAVE_FSTAB_H
|
||||
|
||||
/* Define to 1 if you have the `gethostname' function. */
|
||||
#undef HAVE_GETHOSTNAME
|
||||
|
||||
@@ -291,9 +288,6 @@
|
||||
/* Define to 1 if you have the <sys/utsname.h> header file. */
|
||||
#undef HAVE_SYS_UTSNAME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/vfs.h> header file. */
|
||||
#undef HAVE_SYS_VFS_H
|
||||
|
||||
/* Define to 1 if you have the <sys/wait.h> header file. */
|
||||
#undef HAVE_SYS_WAIT_H
|
||||
|
||||
|
||||
@@ -81,8 +81,10 @@ FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "region_size", "For mirr
|
||||
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunksize", "For snapshots, the unit of data used when tracking changes.")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunk_size", "For snapshots, the unit of data used when tracking changes.")
|
||||
FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start", "Offset within the LV to the start of the segment in current units.")
|
||||
FIELD(SEGS, seg, NUM, "Start", list, 5, segstartpe, "seg_start_pe", "Offset within the LV to the start of the segment in physical extents.")
|
||||
FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size", "Size of segment in current units.")
|
||||
FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags", "Tags, if any.")
|
||||
FIELD(SEGS, seg, STR, "PE Ranges", list, 9, peranges, "seg_pe_ranges", "Ranges of Physical Extents of underlying devices in command line format.")
|
||||
FIELD(SEGS, seg, STR, "Devices", list, 5, devices, "devices", "Underlying devices used with starting extent numbers.")
|
||||
|
||||
FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, "pvseg_start", "Physical Extent number of start of segment.")
|
||||
|
||||
@@ -80,9 +80,8 @@ static int _dev_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute(
|
||||
return dm_report_field_string(rh, field, &name);
|
||||
}
|
||||
|
||||
static int _devices_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute((unused)))
|
||||
static int _format_pvsegs(struct dm_pool *mem, struct dm_report_field *field,
|
||||
const void *data, int range_format)
|
||||
{
|
||||
const struct lv_segment *seg = (const struct lv_segment *) data;
|
||||
unsigned int s;
|
||||
@@ -115,19 +114,32 @@ static int _devices_disp(struct dm_report *rh __attribute((unused)), struct dm_p
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(extent_str, sizeof(extent_str), "(%" PRIu32
|
||||
")", extent) < 0) {
|
||||
if (dm_snprintf(extent_str, sizeof(extent_str),
|
||||
"%s%" PRIu32 "%s",
|
||||
range_format ? ":" : "(", extent,
|
||||
range_format ? "-" : ")") < 0) {
|
||||
log_error("Extent number dm_snprintf failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
|
||||
log_error("dm_pool_grow_object failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (range_format) {
|
||||
if (dm_snprintf(extent_str, sizeof(extent_str),
|
||||
"%" PRIu32, extent + seg->area_len - 1) < 0) {
|
||||
log_error("Extent number dm_snprintf failed");
|
||||
return 0;
|
||||
}
|
||||
if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
|
||||
log_error("dm_pool_grow_object failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((s != seg->area_count - 1) &&
|
||||
!dm_pool_grow_object(mem, ",", 1)) {
|
||||
!dm_pool_grow_object(mem, range_format ? " " : ",", 1)) {
|
||||
log_error("dm_pool_grow_object failed");
|
||||
return 0;
|
||||
}
|
||||
@@ -143,6 +155,20 @@ static int _devices_disp(struct dm_report *rh __attribute((unused)), struct dm_p
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _devices_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute((unused)))
|
||||
{
|
||||
return _format_pvsegs(mem, field, data, 0);
|
||||
}
|
||||
|
||||
static int _peranges_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute((unused)))
|
||||
{
|
||||
return _format_pvsegs(mem, field, data, 1);
|
||||
}
|
||||
|
||||
static int _tags_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute((unused)))
|
||||
@@ -613,6 +639,15 @@ static int _segstart_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
return _size64_disp(rh, mem, field, &start, private);
|
||||
}
|
||||
|
||||
static int _segstartpe_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private)
|
||||
{
|
||||
const struct lv_segment *seg = (const struct lv_segment *) data;
|
||||
|
||||
return dm_report_field_uint32(rh, field, &seg->le);
|
||||
}
|
||||
|
||||
static int _segsize_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private)
|
||||
|
||||
@@ -300,6 +300,8 @@ static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("Created %s", path);
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
if (!dm_set_selinux_context(path, S_IFBLK))
|
||||
return 0;
|
||||
@@ -341,6 +343,8 @@ static int _rename_dev_node(const char *old_name, const char *new_name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("Renamed %s to %s", oldpath, newpath);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -359,6 +363,8 @@ static int _rm_dev_node(const char *dev_name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("Removed %s", path);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -382,6 +388,11 @@ int get_dev_node_read_ahead(const char *dev_name, uint32_t *read_ahead)
|
||||
int fd;
|
||||
long read_ahead_long;
|
||||
|
||||
if (!*dev_name) {
|
||||
log_error("Empty device name passed to BLKRAGET");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((fd = _open_dev_node(dev_name)) < 0)
|
||||
return_0;
|
||||
|
||||
@@ -406,6 +417,11 @@ static int _set_read_ahead(const char *dev_name, uint32_t read_ahead)
|
||||
int fd;
|
||||
long read_ahead_long = (long) read_ahead;
|
||||
|
||||
if (!*dev_name) {
|
||||
log_error("Empty device name passed to BLKRAGET");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((fd = _open_dev_node(dev_name)) < 0)
|
||||
return_0;
|
||||
|
||||
@@ -438,8 +454,8 @@ static int _set_dev_node_read_ahead(const char *dev_name, uint32_t read_ahead,
|
||||
return_0;
|
||||
|
||||
if (current_read_ahead > read_ahead) {
|
||||
log_debug("%s: read ahead %" PRIu32
|
||||
" below minimum of %" PRIu32,
|
||||
log_debug("%s: retaining kernel read ahead of %" PRIu32
|
||||
" (requested %" PRIu32 ")",
|
||||
dev_name, current_read_ahead, read_ahead);
|
||||
return 1;
|
||||
}
|
||||
@@ -521,9 +537,23 @@ static int _stack_node_op(node_op_t type, const char *dev_name, uint32_t major,
|
||||
uint32_t read_ahead_flags)
|
||||
{
|
||||
struct node_op_parms *nop;
|
||||
struct list *noph, *nopht;
|
||||
size_t len = strlen(dev_name) + strlen(old_name) + 2;
|
||||
char *pos;
|
||||
|
||||
/*
|
||||
* Ignore any outstanding operations on the node if deleting it
|
||||
*/
|
||||
if (type == NODE_DEL) {
|
||||
list_iterate_safe(noph, nopht, &_node_ops) {
|
||||
nop = list_item(noph, struct node_op_parms);
|
||||
if (!strcmp(dev_name, nop->dev_name)) {
|
||||
list_del(&nop->list);
|
||||
dm_free(nop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(nop = dm_malloc(sizeof(*nop) + len))) {
|
||||
log_error("Insufficient memory to stack mknod operation");
|
||||
return 0;
|
||||
@@ -565,18 +595,25 @@ static void _pop_node_ops(void)
|
||||
int add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
|
||||
uid_t uid, gid_t gid, mode_t mode)
|
||||
{
|
||||
log_debug("%s: Stacking NODE_ADD (%" PRIu32 ",%" PRIu32 ") %u:%u 0%o",
|
||||
dev_name, major, minor, uid, gid, mode);
|
||||
|
||||
return _stack_node_op(NODE_ADD, dev_name, major, minor, uid, gid, mode,
|
||||
"", 0, 0);
|
||||
}
|
||||
|
||||
int rename_dev_node(const char *old_name, const char *new_name)
|
||||
{
|
||||
log_debug("%s: Stacking NODE_RENAME to %s", old_name, new_name);
|
||||
|
||||
return _stack_node_op(NODE_RENAME, new_name, 0, 0, 0, 0, 0, old_name,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
int rm_dev_node(const char *dev_name)
|
||||
{
|
||||
log_debug("%s: Stacking NODE_DEL (replaces other stacked ops)", dev_name);
|
||||
|
||||
return _stack_node_op(NODE_DEL, dev_name, 0, 0, 0, 0, 0, "", 0, 0);
|
||||
}
|
||||
|
||||
@@ -586,6 +623,9 @@ int set_dev_node_read_ahead(const char *dev_name, uint32_t read_ahead,
|
||||
if (read_ahead == DM_READ_AHEAD_AUTO)
|
||||
return 1;
|
||||
|
||||
log_debug("%s: Stacking NODE_READ_AHEAD %" PRIu32 " (flags=%" PRIu32
|
||||
")", dev_name, read_ahead, read_ahead_flags);
|
||||
|
||||
return _stack_node_op(NODE_READ_AHEAD, dev_name, 0, 0, 0, 0, 0, "",
|
||||
read_ahead, read_ahead_flags);
|
||||
}
|
||||
|
||||
@@ -1160,11 +1160,11 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
|
||||
if (!child->info.inactive_table && !child->info.suspended)
|
||||
continue;
|
||||
|
||||
if (!_resume_node(name, child->info.major, child->info.minor,
|
||||
if (!_resume_node(child->name, child->info.major, child->info.minor,
|
||||
child->props.read_ahead,
|
||||
child->props.read_ahead_flags, &newinfo)) {
|
||||
log_error("Unable to resume %s (%" PRIu32
|
||||
":%" PRIu32 ")", name, child->info.major,
|
||||
":%" PRIu32 ")", child->name, child->info.major,
|
||||
child->info.minor);
|
||||
continue;
|
||||
}
|
||||
@@ -1510,7 +1510,6 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
void *handle = NULL;
|
||||
struct dm_tree_node *child;
|
||||
struct dm_info newinfo;
|
||||
const char *name;
|
||||
|
||||
/* Preload children first */
|
||||
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
|
||||
@@ -1526,11 +1525,6 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
if (dm_tree_node_num_children(child, 0))
|
||||
dm_tree_preload_children(child, uuid_prefix, uuid_prefix_len);
|
||||
|
||||
if (!(name = dm_tree_node_get_name(child))) {
|
||||
stack;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* FIXME Cope if name exists with no uuid? */
|
||||
if (!child->info.exists) {
|
||||
if (!_create_node(child)) {
|
||||
@@ -1553,11 +1547,11 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
if (!child->info.inactive_table && !child->info.suspended)
|
||||
continue;
|
||||
|
||||
if (!_resume_node(name, child->info.major, child->info.minor,
|
||||
if (!_resume_node(child->name, child->info.major, child->info.minor,
|
||||
child->props.read_ahead,
|
||||
child->props.read_ahead_flags, &newinfo)) {
|
||||
log_error("Unable to resume %s (%" PRIu32
|
||||
":%" PRIu32 ")", name, child->info.major,
|
||||
":%" PRIu32 ")", child->name, child->info.major,
|
||||
child->info.minor);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -75,11 +75,10 @@ Change access permission to read-only or read/write.
|
||||
.I \-r, \-\-readahead ReadAheadSectors|auto|none
|
||||
Set read ahead sector count of this logical volume.
|
||||
For volume groups with metadata in lvm1 format, this must
|
||||
be a value between 2 and 120.
|
||||
be a value between 2 and 120 sectors.
|
||||
The default value is "auto" which allows the kernel to choose
|
||||
a suitable value automatically.
|
||||
"None" is equivalent to specifying zero.
|
||||
N.B. This setting is currently disregarded and "auto" is always used.
|
||||
.TP
|
||||
.I \-\-refresh
|
||||
If the logical volume is active, reload its metadata.
|
||||
|
||||
@@ -125,7 +125,6 @@ be a value between 2 and 120.
|
||||
The default value is "auto" which allows the kernel to choose
|
||||
a suitable value automatically.
|
||||
"None" is equivalent to specifying zero.
|
||||
N.B. This setting is currently disregarded and "auto" is always used.
|
||||
.TP
|
||||
.I \-R, \-\-regionsize MirrorLogRegionSize
|
||||
A mirror is divided into regions of this size (in MB), and the mirror log
|
||||
|
||||
@@ -20,4 +20,6 @@ include $(top_srcdir)/make.tmpl
|
||||
install:
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) lvm_dump.sh \
|
||||
$(sbindir)/lvmdump
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) fsadm.sh \
|
||||
$(sbindir)/fsadm
|
||||
|
||||
|
||||
345
scripts/fsadm.sh
Normal file
345
scripts/fsadm.sh
Normal file
@@ -0,0 +1,345 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (C) 2007 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 General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Author: Zdenek Kabelac <zkabelac@redhat.com>
|
||||
#
|
||||
# Script for resizing devices (usable for LVM resize)
|
||||
#
|
||||
# Needed utilities:
|
||||
# mount, umount, grep, readlink, blockdev, blkid, fsck, xfs_check
|
||||
#
|
||||
# ext2/ext3: resize2fs, tune2fs
|
||||
# reiserfs: resize_reiserfs, reiserfstune
|
||||
# xfs: xfs_growfs, xfs_info
|
||||
#
|
||||
|
||||
TOOL=fsadm
|
||||
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/sbin:$PATH
|
||||
|
||||
# utilities
|
||||
TUNE_EXT=tune2fs
|
||||
RESIZE_EXT=resize2fs
|
||||
TUNE_REISER=reiserfstune
|
||||
RESIZE_REISER=resize_reiserfs
|
||||
TUNE_XFS=xfs_info
|
||||
RESIZE_XFS=xfs_growfs
|
||||
|
||||
MOUNT=mount
|
||||
UMOUNT=umount
|
||||
MKDIR=mkdir
|
||||
RM=rm
|
||||
BLOCKDEV=blockdev
|
||||
BLKID=blkid
|
||||
GREP=grep
|
||||
READLINK=readlink
|
||||
FSCK=fsck
|
||||
XFS_CHECK=xfs_check
|
||||
|
||||
YES=
|
||||
DRY=0
|
||||
VERB=0
|
||||
FORCE=
|
||||
EXTOFF=0
|
||||
FSTYPE=unknown
|
||||
VOLUME=unknown
|
||||
TEMPDIR="${TMPDIR:-/tmp}/${TOOL}_${RANDOM}$$/m"
|
||||
BLOCKSIZE=
|
||||
BLOCKCOUNT=
|
||||
MOUNTPOINT=
|
||||
MOUNTED=
|
||||
REMOUNT=
|
||||
|
||||
IFS_OLD=$IFS
|
||||
|
||||
tool_usage() {
|
||||
echo "${TOOL}: Utility to resize or check the filesystem on a device"
|
||||
echo
|
||||
echo " ${TOOL} [options] check device"
|
||||
echo " - Check the filesystem on device using fsck"
|
||||
echo
|
||||
echo " ${TOOL} [options] resize device [new_size[BKMGT]]"
|
||||
echo " - Change the size of the filesystem on device to new_size"
|
||||
echo
|
||||
echo " Options:"
|
||||
echo " -h | --help Show this help message"
|
||||
echo " -v | --verbose Be verbose"
|
||||
echo " -e | --ext-offline unmount filesystem before Ext2/3 resize"
|
||||
echo " -f | --force Bypass sanity checks"
|
||||
echo " -n | --dry-run Print commands without running them"
|
||||
echo " -y | --yes Answer \"yes\" at any prompts"
|
||||
echo
|
||||
echo " new_size - Absolute number of filesystem blocks to be in the filesystem,"
|
||||
echo " or an absolute size using a suffix (in powers of 1024)."
|
||||
echo " If new_size is not supplied, the whole device is used."
|
||||
|
||||
exit
|
||||
}
|
||||
|
||||
verbose() {
|
||||
test "$VERB" -eq 1 && echo "$TOOL: $@" || true
|
||||
}
|
||||
|
||||
error() {
|
||||
echo "$TOOL: $@" >&2
|
||||
cleanup 1
|
||||
}
|
||||
|
||||
dry() {
|
||||
verbose "Executing $@"
|
||||
test "$DRY" -ne 0 && return 0
|
||||
$@
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
trap '' 2
|
||||
# reset MOUNTPOINT - avoid recursion
|
||||
test "$MOUNTPOINT" = "$TEMPDIR" && MOUNTPOINT="" temp_umount
|
||||
if [ -n "$REMOUNT" ]; then
|
||||
verbose "Remounting unmounted filesystem back"
|
||||
dry $MOUNT "$VOLUME" "$MOUNTED"
|
||||
fi
|
||||
IFS=$IFS_OLD
|
||||
trap 2
|
||||
exit $1
|
||||
}
|
||||
|
||||
# convert parameters from Mega/Kilo/Bytes/Blocks
|
||||
# and print number of bytes
|
||||
decode_size() {
|
||||
case "$1" in
|
||||
*[tT]) NEWSIZE=$(( ${1%[tT]} * 1099511627776 )) ;;
|
||||
*[gG]) NEWSIZE=$(( ${1%[gG]} * 1073741824 )) ;;
|
||||
*[mM]) NEWSIZE=$(( ${1%[mM]} * 1048576 )) ;;
|
||||
*[kK]) NEWSIZE=$(( ${1%[kK]} * 1024 )) ;;
|
||||
*[bB]) NEWSIZE=${1%[bB]} ;;
|
||||
*) NEWSIZE=$(( $1 * $2 )) ;;
|
||||
esac
|
||||
#NEWBLOCKCOUNT=$(round_block_size $NEWSIZE $2)
|
||||
NEWBLOCKCOUNT=$(( $NEWSIZE / $2 ))
|
||||
}
|
||||
|
||||
# detect filesystem on the given device
|
||||
# dereference device name if it is symbolic link
|
||||
detect_fs() {
|
||||
VOLUME=$($READLINK -e -n "$1")
|
||||
# use /dev/null as cache file to be sure about the result
|
||||
FSTYPE=$($BLKID -c /dev/null -o value -s TYPE "$VOLUME" || error "Cannot get FSTYPE of \"$VOLUME\"")
|
||||
verbose "\"$FSTYPE\" filesystem found on \"$VOLUME\""
|
||||
}
|
||||
|
||||
# check if the given device is already mounted and where
|
||||
detect_mounted() {
|
||||
MOUNTED=$($MOUNT | $GREP "$VOLUME")
|
||||
MOUNTED=${MOUNTED##* on }
|
||||
MOUNTED=${MOUNTED% type *} # allow type in the mount name
|
||||
test -n "$MOUNTED"
|
||||
}
|
||||
|
||||
# get the full size of device in bytes
|
||||
detect_device_size() {
|
||||
DEVSIZE=$($BLOCKDEV --getsize64 "$VOLUME") || error "Cannot read device \"$VOLUME\""
|
||||
}
|
||||
|
||||
# round up $1 / $2
|
||||
# could be needed to gaurantee 'at least given size'
|
||||
# but it makes many troubles
|
||||
round_up_block_size() {
|
||||
echo $(( ($1 + $2 - 1) / $2 ))
|
||||
}
|
||||
|
||||
temp_mount() {
|
||||
dry $MKDIR -p -m 0000 "$TEMPDIR" || error "Failed to create $TEMPDIR"
|
||||
dry $MOUNT "$VOLUME" "$TEMPDIR" || error "Failed to mount $TEMPDIR"
|
||||
}
|
||||
|
||||
temp_umount() {
|
||||
dry $UMOUNT "$TEMPDIR" && dry $RM -r "${TEMPDIR%%m}" || error "Failed to umount $TEMPDIR"
|
||||
}
|
||||
|
||||
yes_no() {
|
||||
echo -n "$@? [Y|n] "
|
||||
if [ -n "$YES" ]; then
|
||||
ANS="y"; echo -n $ANS
|
||||
else
|
||||
read -n 1 ANS
|
||||
fi
|
||||
test -n "$ANS" && echo
|
||||
case "$ANS" in
|
||||
"y" | "Y" | "" ) return 0 ;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
try_umount() {
|
||||
yes_no "Do you want to unmount \"$MOUNTED\"" && dry $UMOUNT "$MOUNTED" && return 0
|
||||
error "Cannot proceed test with mounted filesystem \"$MOUNTED\""
|
||||
}
|
||||
|
||||
validate_parsing() {
|
||||
test -n "$BLOCKSIZE" -a -n "$BLOCKCOUNT" || error "Cannot parse $1 output"
|
||||
}
|
||||
####################################
|
||||
# Resize ext2/ext3 filesystem
|
||||
# - unmounted or mounted for upsize
|
||||
# - unmounted for downsize
|
||||
####################################
|
||||
resize_ext() {
|
||||
verbose "Parsing $TUNE_EXT -l \"$VOLUME\""
|
||||
for i in $($TUNE_EXT -l "$VOLUME"); do
|
||||
case "$i" in
|
||||
"Block size"*) BLOCKSIZE=${i##* } ;;
|
||||
"Block count"*) BLOCKCOUNT=${i##* } ;;
|
||||
esac
|
||||
done
|
||||
validate_parsing $TUNE_EXT
|
||||
decode_size $1 $BLOCKSIZE
|
||||
FSFORCE=$FORCE
|
||||
|
||||
if [ $NEWBLOCKCOUNT -lt $BLOCKCOUNT -o $EXTOFF -eq 1 ]; then
|
||||
detect_mounted && verbose "$RESIZE_EXT needs unmounted filesystem" && try_umount
|
||||
REMOUNT=$MOUNTED
|
||||
# CHECKME: after umount resize2fs requires fsck or -f flag.
|
||||
FSFORCE="-f"
|
||||
fi
|
||||
|
||||
verbose "Resizing \"$VOLUME\" $BLOCKCOUNT -> $NEWBLOCKCOUNT blocks ($NEWSIZE bytes, bs:$BLOCKSIZE)"
|
||||
dry $RESIZE_EXT $FSFORCE "$VOLUME" $NEWBLOCKCOUNT
|
||||
}
|
||||
|
||||
#############################
|
||||
# Resize reiserfs filesystem
|
||||
# - unmounted for upsize
|
||||
# - unmounted for downsize
|
||||
#############################
|
||||
resize_reiser() {
|
||||
detect_mounted
|
||||
if [ -n "$MOUNTED" ]; then
|
||||
verbose "ReiserFS resizes only unmounted filesystem"
|
||||
try_umount
|
||||
REMOUNT=$MOUNTED
|
||||
fi
|
||||
verbose "Parsing $TUNE_REISER \"$VOLUME\""
|
||||
for i in $($TUNE_REISER "$VOLUME"); do
|
||||
case "$i" in
|
||||
"Blocksize"*) BLOCKSIZE=${i##*: } ;;
|
||||
"Count of blocks"*) BLOCKCOUNT=${i##*: } ;;
|
||||
esac
|
||||
done
|
||||
validate_parsing $TUNE_REISER
|
||||
decode_size $1 $BLOCKSIZE
|
||||
verbose "Resizing \"$VOLUME\" $BLOCKCOUNT -> $NEWBLOCKCOUNT blocks ($NEWSIZE bytes, bs: $NEWBLOCKCOUNT)"
|
||||
if [ -n "$YES" ]; then
|
||||
dry echo y | $RESIZE_REISER -s $NEWSIZE "$VOLUME"
|
||||
else
|
||||
dry $RESIZE_REISER -s $NEWSIZE "$VOLUME"
|
||||
fi
|
||||
}
|
||||
|
||||
########################
|
||||
# Resize XFS filesystem
|
||||
# - mounted for upsize
|
||||
# - can not downsize
|
||||
########################
|
||||
resize_xfs() {
|
||||
detect_mounted
|
||||
MOUNTPOINT=$MOUNTED
|
||||
if [ -z "$MOUNTED" ]; then
|
||||
MOUNTPOINT=$TEMPDIR
|
||||
temp_mount || error "Cannot mount Xfs filesystem"
|
||||
fi
|
||||
verbose "Parsing $TUNE_XFS \"$MOUNTPOINT\""
|
||||
for i in $($TUNE_XFS "$MOUNTPOINT"); do
|
||||
case "$i" in
|
||||
"data"*) BLOCKSIZE=${i##*bsize=} ; BLOCKCOUNT=${i##*blocks=} ;;
|
||||
esac
|
||||
done
|
||||
BLOCKSIZE=${BLOCKSIZE%%[^0-9]*}
|
||||
BLOCKCOUNT=${BLOCKCOUNT%%[^0-9]*}
|
||||
validate_parsing $TUNE_XFS
|
||||
decode_size $1 $BLOCKSIZE
|
||||
if [ $NEWBLOCKCOUNT -gt $BLOCKCOUNT ]; then
|
||||
verbose "Resizing Xfs mounted on \"$MOUNTPOINT\" to fill device \"$VOLUME\""
|
||||
dry $RESIZE_XFS $MOUNTPOINT
|
||||
elif [ $NEWBLOCKCOUNT -eq $BLOCKCOUNT ]; then
|
||||
verbose "Xfs filesystem already has the right size"
|
||||
else
|
||||
error "Xfs filesystem shrinking is unsupported"
|
||||
fi
|
||||
}
|
||||
|
||||
####################
|
||||
# Resize filesystem
|
||||
####################
|
||||
resize() {
|
||||
detect_fs "$1"
|
||||
detect_device_size
|
||||
verbose "Device \"$VOLUME\" has $DEVSIZE bytes"
|
||||
# if the size parameter is missing use device size
|
||||
NEWSIZE=$2
|
||||
test -z $NEWSIZE && NEWSIZE=${DEVSIZE}b
|
||||
trap cleanup 2
|
||||
#IFS=$'\n' # don't use bash-ism ??
|
||||
IFS="$(printf \"\\n\")" # needed for parsing output
|
||||
case "$FSTYPE" in
|
||||
"ext3"|"ext2") resize_ext $NEWSIZE ;;
|
||||
"reiserfs") resize_reiser $NEWSIZE ;;
|
||||
"xfs") resize_xfs $NEWSIZE ;;
|
||||
*) error "Filesystem \"$FSTYPE\" on device \"$VOLUME\" is not supported by this tool" ;;
|
||||
esac || error "Resize $FSTYPE failed"
|
||||
cleanup
|
||||
}
|
||||
|
||||
###################
|
||||
# Check filesystem
|
||||
###################
|
||||
check() {
|
||||
detect_fs "$1"
|
||||
case "$FSTYPE" in
|
||||
"xfs") dry $XFS_CHECK "$VOLUME" ;;
|
||||
*) dry $FSCK $YES "$VOLUME" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
#############################
|
||||
# start point of this script
|
||||
# - parsing parameters
|
||||
#############################
|
||||
if [ "$1" = "" ] ; then
|
||||
tool_usage
|
||||
fi
|
||||
|
||||
while [ "$1" != "" ]
|
||||
do
|
||||
case "$1" in
|
||||
"-h"|"--help") tool_usage ;;
|
||||
"-v"|"--verbose") VERB=1 ;;
|
||||
"-n"|"--dry-run") DRY=1 ;;
|
||||
"-f"|"--force") FORCE="-f" ;;
|
||||
"-e"|"--ext-offline") EXTOFF=1 ;;
|
||||
"-y"|"--yes") YES="-y" ;;
|
||||
"check") shift; CHECK=$1 ;;
|
||||
"resize") shift; RESIZE=$1; shift; NEWSIZE=$1 ;;
|
||||
*) error "Wrong argument \"$1\". (see: $TOOL --help)"
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -n "$CHECK" ]; then
|
||||
check "$CHECK"
|
||||
elif [ -n "$RESIZE" ]; then
|
||||
resize "$RESIZE" "$NEWSIZE"
|
||||
else
|
||||
error "Missing command. (see: $TOOL --help)"
|
||||
fi
|
||||
@@ -16,10 +16,6 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
ifeq ("@FSADM@", "yes")
|
||||
SUBDIRS += fsadm
|
||||
endif
|
||||
|
||||
SOURCES =\
|
||||
dumpconfig.c \
|
||||
formats.c \
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004 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 General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
SOURCES = fsadm.c
|
||||
|
||||
TARGETS = fsadm
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
fsadm: $(OBJECTS)
|
||||
$(CC) -o $@ $(CFLAGS) $(OBJECTS) -rdynamic
|
||||
|
||||
install: fsadm
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) fsadm \
|
||||
$(sbindir)/fsadm
|
||||
|
||||
@@ -1,347 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2004 Red Hat GmbH. All rights reserved.
|
||||
* Copyright (C) 2007 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 General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* FIXME: pass smart resizer arguments through from lvresize
|
||||
* (eg, for xfs_growfs)
|
||||
*/
|
||||
|
||||
/* FIXME All funcs to return 0 on success or an error from errno.h on failure */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#define MAX_ARGS 8
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <inttypes.h>
|
||||
#include <fstab.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/vfs.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "last-path-component.h"
|
||||
|
||||
#define log_error(str, x...) fprintf(stderr, "%s(%u): " str "\n", __FILE__, __LINE__, x)
|
||||
|
||||
/* Filesystem related information */
|
||||
struct fsinfo {
|
||||
struct fstab *fsent;
|
||||
struct statfs statfs;
|
||||
uint64_t new_size;
|
||||
const char *cmd;
|
||||
};
|
||||
|
||||
static void _usage(const char *cmd)
|
||||
{
|
||||
log_error("Usage: %s [check <filesystem> | resize <filesystem> <size>]",
|
||||
last_path_component(cmd));
|
||||
}
|
||||
|
||||
/* FIXME Make this more robust - /proc, multiple mounts, TMPDIR + security etc. */
|
||||
/* FIXME Ensure filesystem is not mounted anywhere before running fsck/resize */
|
||||
/* Gather filesystem information (VFS type, special file and block size) */
|
||||
static int _get_fsinfo(const char *file, struct fsinfo *fsinfo)
|
||||
{
|
||||
char *dir, template[] = "/tmp/fscmd_XXXXXX";
|
||||
struct stat info;
|
||||
int ret = 0;
|
||||
|
||||
if (stat(file, &info)) {
|
||||
log_error("%s: stat failed: %s", file, strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
|
||||
/* FIXME: are we limited to /etc/fstab entries ? */
|
||||
if (!(fsinfo->fsent = info.st_rdev ? getfsspec(file) : getfsfile(file))) {
|
||||
log_error("%s: getfsspec/getfsfile failed: "
|
||||
"Missing from /etc/fstab?", file);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* FIXME: any other way to retrieve fs blocksize avoiding mounting ? */
|
||||
if (!(dir = (mkdtemp(template)))) {
|
||||
log_error("%s: mkdtemp failed: %s", template, strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
|
||||
if (mount(fsinfo->fsent->fs_spec, dir, fsinfo->fsent->fs_vfstype,
|
||||
MS_RDONLY, NULL)) {
|
||||
log_error("%s: mount %s failed: %s", fsinfo->fsent->fs_spec,
|
||||
dir, strerror(errno));
|
||||
ret = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (statfs(dir, &fsinfo->statfs)) {
|
||||
log_error("%s: statfs failed: %s", dir, strerror(errno));
|
||||
ret = errno;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
out1:
|
||||
if (umount(dir))
|
||||
log_error("%s: umount failed: %s", dir, strerror(errno));
|
||||
|
||||
out:
|
||||
if (rmdir(dir))
|
||||
log_error("%s: rmdir failed: %s", dir, strerror(errno));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum {
|
||||
BLOCKS,
|
||||
KILOBYTES
|
||||
};
|
||||
|
||||
#define LEN 32 /* Length of temporary string */
|
||||
|
||||
/* Create size string in units of blocks or kilobytes
|
||||
* (size expected in kilobytes)
|
||||
*/
|
||||
static char *_size_str(struct fsinfo *fsinfo, int unit)
|
||||
{
|
||||
uint64_t new_size = fsinfo->new_size;
|
||||
static char s[LEN];
|
||||
|
||||
/* Avoid switch() as long as there's only 2 cases */
|
||||
snprintf(s, LEN, "%" PRIu64,
|
||||
unit == BLOCKS ? new_size / (fsinfo->statfs.f_bsize >> 10) :
|
||||
new_size);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Allocate memory and store string updating string pointer */
|
||||
static int _store(char **arg, char **str)
|
||||
{
|
||||
size_t len = 0;
|
||||
char *s = *str;
|
||||
|
||||
while (*s && *s != '%' && *(s++) != ' ')
|
||||
len++;
|
||||
|
||||
if ((*arg = (char *) malloc(len + 1))) {
|
||||
strncpy(*arg, *str, len);
|
||||
(*arg)[len] = '\0';
|
||||
*str = s - 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Construct a new argument vector for the real external command */
|
||||
static int _new_argv(char **new_argv, struct fsinfo *fsinfo)
|
||||
{
|
||||
int i = 0, b = 0, d = 0, k = 0, m = 0;
|
||||
char *s1;
|
||||
char *s = (char *) fsinfo->cmd;
|
||||
|
||||
if (!s || !strlen(s))
|
||||
return 1;
|
||||
|
||||
do {
|
||||
switch (*s) {
|
||||
case ' ':
|
||||
break;
|
||||
|
||||
case '%':
|
||||
s++;
|
||||
|
||||
switch (tolower(*s)) {
|
||||
case 'b':
|
||||
s1 = _size_str(fsinfo, BLOCKS);
|
||||
if (b++ + k || _store(&new_argv[i++], &s1))
|
||||
goto error;
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
s1 = _size_str(fsinfo, KILOBYTES);
|
||||
if (b + k++ || _store(&new_argv[i++], &s1))
|
||||
goto error;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
s1 = fsinfo->fsent->fs_spec;
|
||||
if (d++ + m || _store(&new_argv[i++], &s1))
|
||||
goto error;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
s1 = fsinfo->fsent->fs_file;
|
||||
if (d + m++ || _store(&new_argv[i++], &s1))
|
||||
goto error;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
if (_store(&new_argv[i++], &s))
|
||||
goto error;
|
||||
}
|
||||
} while (*++s);
|
||||
|
||||
new_argv[i] = NULL;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
new_argv[i] = NULL;
|
||||
log_error("Failed constructing arguments for %s", s);
|
||||
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get filesystem command arguments derived from a command definition string
|
||||
*
|
||||
* Command definition syntax: 'cmd [-option]{0,} [(option)argument]{0,}'
|
||||
*
|
||||
* (option)argument can be: '%{bdkm}'
|
||||
*
|
||||
* Command definition is parsed into argument strings of
|
||||
* an argument vector with:
|
||||
*
|
||||
* %b replaced by the size in filesystem blocks
|
||||
* %k replaced by the size in kilobytes
|
||||
* %d replaced by the name of the device special of the LV
|
||||
* %m replaced by the mountpoint of the filesystem
|
||||
*
|
||||
*/
|
||||
static int _get_cmd(char *command, struct fsinfo *fsinfo)
|
||||
{
|
||||
const char *vfstype = fsinfo->fsent->fs_vfstype;
|
||||
struct fscmd {
|
||||
const char *vfstype;
|
||||
const char *fsck;
|
||||
const char *fsresize;
|
||||
} fscmds[] = {
|
||||
{ "ext2", "fsck -fy %d", "ext2resize %d %b"},
|
||||
{"ext3", "fsck -fy %d", "ext2resize %d %b"},
|
||||
{"reiserfs", "", "resize_reiserfs -s%k %d"},
|
||||
{"xfs", "", "xfs_growfs -D %b %m"}, /* simple xfs grow */
|
||||
{NULL, NULL, NULL},
|
||||
}, *p = &fscmds[0];
|
||||
|
||||
for (; p->vfstype; p++) {
|
||||
if (!strcmp(vfstype, p->vfstype)) {
|
||||
if (!strcmp(command, "resize"))
|
||||
fsinfo->cmd = p->fsresize;
|
||||
else if (!strcmp(command, "check"))
|
||||
fsinfo->cmd = p->fsck;
|
||||
else {
|
||||
log_error("Unrecognised command: %s", command);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fsinfo->cmd) {
|
||||
log_error("%s: Unrecognised filesystem type", vfstype);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Collapse multiple slashes */
|
||||
static char *_collapse_slashes(char *path)
|
||||
{
|
||||
char *s = path;
|
||||
|
||||
/* Slight overhead but short ;) */
|
||||
while ((s = strchr(s, '/')) && *(s + 1))
|
||||
*(s + 1) == '/' ? memmove(s, s + 1, strlen(s)) : s++;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* Free the argument array */
|
||||
static void _free_argv(char **new_argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; new_argv[i]; i++)
|
||||
free(new_argv[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* check/resize a filesystem
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret = 0;
|
||||
struct fsinfo fsinfo;
|
||||
char *new_argv[MAX_ARGS];
|
||||
char *command, *path;
|
||||
|
||||
if (argc < 3)
|
||||
goto error;
|
||||
|
||||
command = argv[1];
|
||||
path = _collapse_slashes(argv[2]);
|
||||
|
||||
if (!strcmp(command, "resize")) {
|
||||
if (argc != 4)
|
||||
goto error;
|
||||
/* FIXME sanity checks */
|
||||
fsinfo.new_size = strtoul(argv[3], NULL, 10);
|
||||
} else if (argc != 3)
|
||||
goto error;
|
||||
|
||||
/* Retrieve filesystem information (block size...) */
|
||||
if ((ret = _get_fsinfo(path, &fsinfo))) {
|
||||
log_error("Can't get filesystem information from %s", path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get filesystem command info */
|
||||
if ((ret = _get_cmd(command, &fsinfo))) {
|
||||
log_error("Can't get filesystem command for %s", command);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (_new_argv(new_argv, &fsinfo))
|
||||
return EINVAL;
|
||||
|
||||
if (!new_argv[0])
|
||||
return 0;
|
||||
|
||||
execvp(new_argv[0], new_argv);
|
||||
ret = errno;
|
||||
log_error("%s: execvp %s failed", new_argv[0], strerror(errno));
|
||||
_free_argv(new_argv);
|
||||
|
||||
return ret;
|
||||
|
||||
error:
|
||||
_usage(argv[0]);
|
||||
return EINVAL;
|
||||
}
|
||||
@@ -372,6 +372,7 @@ static int lvchange_readahead(struct cmd_context *cmd,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
unsigned read_ahead = 0;
|
||||
unsigned pagesize = (unsigned) lvm_getpagesize() >> SECTOR_SHIFT;
|
||||
|
||||
read_ahead = arg_uint_value(cmd, readahead_ARG, 0);
|
||||
|
||||
@@ -382,6 +383,13 @@ static int lvchange_readahead(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (read_ahead != DM_READ_AHEAD_AUTO &&
|
||||
read_ahead != DM_READ_AHEAD_NONE && read_ahead % pagesize) {
|
||||
read_ahead = (read_ahead / pagesize) * pagesize;
|
||||
log_verbose("Rounding down readahead to %u sectors, a multiple "
|
||||
"of page size %u.", read_ahead, pagesize);
|
||||
}
|
||||
|
||||
if (lv->read_ahead == read_ahead) {
|
||||
log_error("Read ahead is already %u for \"%s\"",
|
||||
read_ahead, lv->name);
|
||||
|
||||
@@ -339,7 +339,7 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
1, lp->mirrors - 1,
|
||||
corelog ? 0U : 1U,
|
||||
lv->le_count, lp->pvh, lp->alloc,
|
||||
parallel_areas)))
|
||||
1, parallel_areas)))
|
||||
return_0;
|
||||
|
||||
lp->region_size = adjusted_mirror_region_size(lv->vg->extent_size,
|
||||
@@ -385,7 +385,7 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
|
||||
if (!(ah = allocate_extents(lv->vg, NULL, lp->segtype, 0,
|
||||
0, 1, 0, lp->pvh, lp->alloc,
|
||||
parallel_areas))) {
|
||||
1, parallel_areas))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -333,6 +333,7 @@ static int _lvcreate_params(struct lvcreate_params *lp, struct cmd_context *cmd,
|
||||
int argc, char **argv)
|
||||
{
|
||||
int contiguous;
|
||||
unsigned pagesize;
|
||||
|
||||
memset(lp, 0, sizeof(*lp));
|
||||
|
||||
@@ -462,8 +463,17 @@ static int _lvcreate_params(struct lvcreate_params *lp, struct cmd_context *cmd,
|
||||
/*
|
||||
* Read ahead.
|
||||
*/
|
||||
if (arg_count(cmd, readahead_ARG))
|
||||
if (arg_count(cmd, readahead_ARG)) {
|
||||
lp->read_ahead = arg_uint_value(cmd, readahead_ARG, 0);
|
||||
pagesize = lvm_getpagesize() >> SECTOR_SHIFT;
|
||||
if (lp->read_ahead != DM_READ_AHEAD_AUTO &&
|
||||
lp->read_ahead != DM_READ_AHEAD_NONE &&
|
||||
lp->read_ahead % pagesize) {
|
||||
lp->read_ahead = (lp->read_ahead / pagesize) * pagesize;
|
||||
log_verbose("Rounding down readahead to %u sectors, a multiple "
|
||||
"of page size %u.", lp->read_ahead, pagesize);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Permissions.
|
||||
@@ -740,7 +750,7 @@ static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
|
||||
|
||||
if (!(ah = allocate_extents(vg, NULL, lp->segtype, lp->stripes,
|
||||
lp->mirrors, lp->corelog ? 0U : 1U,
|
||||
lp->extents, pvh, lp->alloc, NULL)))
|
||||
lp->extents, pvh, lp->alloc, 1, NULL)))
|
||||
return_0;
|
||||
|
||||
lp->region_size = adjusted_mirror_region_size(vg->extent_size,
|
||||
|
||||
@@ -161,6 +161,11 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
|
||||
log_print("Skipping locked LV %s", lv->name);
|
||||
continue;
|
||||
}
|
||||
/* FIXME Just insert the layer below - no allocation */
|
||||
// This knows nothing about pvmove
|
||||
// insert_layer_for_segments_on_pv(cmd, lv, source_pvl, lv_mirr, *lvs_changed)
|
||||
// - for each lv segment using that pv
|
||||
// - call new fn insert_internal_layer()
|
||||
if (!insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv,
|
||||
allocatable_pvs, alloc,
|
||||
*lvs_changed)) {
|
||||
@@ -175,6 +180,10 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME Do allocation and convert to mirror */
|
||||
// again, this knows nothing about pvmove: it's a normal lvconvert lv_mirr to mirror with in-core log
|
||||
// - a flag passed in requires that parent segs get split after the allocation (with failure if not possible)
|
||||
|
||||
return lv_mirr;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,8 +59,10 @@ static int _pvsegs_sub_single(struct cmd_context *cmd __attribute((unused)),
|
||||
struct pv_segment *pvseg, void *handle)
|
||||
{
|
||||
int ret = ECMD_PROCESSED;
|
||||
struct lv_segment *seg = pvseg->lvseg;
|
||||
|
||||
if (!report_object(handle, vg, NULL, pvseg->pv, NULL, pvseg))
|
||||
if (!report_object(handle, vg, seg ? seg->lv : NULL, pvseg->pv, seg,
|
||||
pvseg))
|
||||
ret = ECMD_FAILED;
|
||||
|
||||
return ret;
|
||||
@@ -279,21 +281,22 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
|
||||
report_type |= LVS;
|
||||
if (report_type & PVSEGS)
|
||||
report_type |= PVS;
|
||||
if ((report_type & LVS) && (report_type & PVS)) {
|
||||
if ((report_type & LVS) && (report_type & PVS) && !args_are_pvs) {
|
||||
log_error("Can't report LV and PV fields at the same time");
|
||||
dm_report_free(report_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Change report type if fields specified makes this necessary */
|
||||
if (report_type & SEGS)
|
||||
report_type = SEGS;
|
||||
else if (report_type & LVS)
|
||||
report_type = LVS;
|
||||
else if (report_type & PVSEGS)
|
||||
if ((report_type & PVSEGS) ||
|
||||
(report_type & PVS) && (report_type & LVS))
|
||||
report_type = PVSEGS;
|
||||
else if (report_type & PVS)
|
||||
report_type = PVS;
|
||||
else if (report_type & SEGS)
|
||||
report_type = SEGS;
|
||||
else if (report_type & LVS)
|
||||
report_type = LVS;
|
||||
|
||||
switch (report_type) {
|
||||
case LVS:
|
||||
|
||||
Reference in New Issue
Block a user