1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

Fix operation node stacking for consecutive dm ops

With the ability to stack many operations in one udev transaction -
in same cases we are adding and removing same device at the same time
(i.e. deactivate followed by activate).

This leads to a problem of checking stacked operations:
i.e. remove /dev/node1 followed by create /dev/node1

If the node creation is handled with udev - there is a problem as
stacked operation gives warning about existing node1 and will try to
remove it - while next operation needs to recreate it.

Current code removes all previous stacked operation if the fs op is
FS_DEL - patch adds similar behavior for FS_ADD - it will try to
remove any 'delete' operation if udev is in use.

For FS_RENAME operation it seems to be more complex. But as we
are always stacking FS_READ_AHEAD after FS_ADD operation -
should be safe to remove all previous operation on the node
when udev is running.

Code does same checking for stacking libdm and liblvm operations.

As a very simple optimization counters were added for each stacked ops
type to avoid unneeded list scans if some operation does not exists in
the list.

Enable skipping of fs_unlock() (udev sync) if only DEL operations are staked.
as we do not use lv_info for already deleted nodes.
This commit is contained in:
Zdenek Kabelac 2011-02-04 19:14:39 +00:00
parent 2b29daaaa6
commit f5f6dcbc62
4 changed files with 147 additions and 14 deletions

View File

@ -1,5 +1,6 @@
Version 2.02.83 - Version 2.02.83 -
=================================== ===================================
Fix operation node stacking for consecutive dm ops.
Increase hash table size to 1024 lv names and 64 pv uuids. Increase hash table size to 1024 lv names and 64 pv uuids.
Remove fs_unlock() from lv_resume path. Remove fs_unlock() from lv_resume path.
Fix wipe size when setting up mda. Fix wipe size when setting up mda.

View File

@ -469,7 +469,7 @@ int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, unsigned o
if (with_open_count) { if (with_open_count) {
if (locking_is_clustered()) if (locking_is_clustered())
sync_local_dev_names(cmd); /* Wait to have udev in sync */ sync_local_dev_names(cmd); /* Wait to have udev in sync */
else //if (fs_has_non_delete_ops()) else if (fs_has_non_delete_ops())
fs_unlock(); /* For non clustered - wait if there are non-delete ops */ fs_unlock(); /* For non clustered - wait if there are non-delete ops */
} }

View File

@ -257,7 +257,8 @@ static int _rm_link(const char *dev_dir, const char *vg_name,
typedef enum { typedef enum {
FS_ADD, FS_ADD,
FS_DEL, FS_DEL,
FS_RENAME FS_RENAME,
NUM_FS_OPS
} fs_op_t; } fs_op_t;
static int _do_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name, static int _do_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
@ -283,12 +284,18 @@ static int _do_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
if (!_mk_link(dev_dir, vg_name, lv_name, dev, check_udev)) if (!_mk_link(dev_dir, vg_name, lv_name, dev, check_udev))
stack; stack;
default:;
} }
return 1; return 1;
} }
static DM_LIST_INIT(_fs_ops); static DM_LIST_INIT(_fs_ops);
/*
* Count number of stacked fs_op_t operations to allow to skip dm_list search.
* FIXME: handling of FS_RENAME
*/
static int _count_fs_ops[NUM_FS_OPS];
struct fs_op_parms { struct fs_op_parms {
struct dm_list list; struct dm_list list;
@ -309,15 +316,84 @@ static void _store_str(char **pos, char **ptr, const char *str)
*pos += strlen(*ptr) + 1; *pos += strlen(*ptr) + 1;
} }
static void _del_fs_op(struct fs_op_parms *fsp)
{
_count_fs_ops[fsp->type]--;
dm_list_del(&fsp->list);
dm_free(fsp);
}
/* Check if there is other the type of fs operation stacked */
static int _other_fs_ops(fs_op_t type)
{
int i;
for (i = 0; i < NUM_FS_OPS; i++)
if (type != i && _count_fs_ops[i])
return 1;
return 0;
}
/* Check if udev is supposed to create nodes */
static int _check_udev(int check_udev)
{
return check_udev && dm_udev_get_sync_support() && dm_udev_get_checking();
}
/* FIXME: duplication of the code from libdm-common.c */
static int _stack_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name, static int _stack_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
const char *lv_name, const char *dev, const char *lv_name, const char *dev,
const char *old_lv_name, int check_udev) const char *old_lv_name, int check_udev)
{ {
struct dm_list *fsph, *fspht;
struct fs_op_parms *fsp; struct fs_op_parms *fsp;
size_t len = strlen(dev_dir) + strlen(vg_name) + strlen(lv_name) + size_t len = strlen(dev_dir) + strlen(vg_name) + strlen(lv_name) +
strlen(dev) + strlen(old_lv_name) + 5; strlen(dev) + strlen(old_lv_name) + 5;
char *pos; char *pos;
if ((type == FS_DEL) && _other_fs_ops(type))
/*
* Ignore any outstanding operations on the fs_op if deleting it.
*/
dm_list_iterate_safe(fsph, fspht, &_fs_ops) {
fsp = dm_list_item(fsph, struct fs_op_parms);
if (!strcmp(lv_name, fsp->lv_name) &&
!strcmp(vg_name, fsp->vg_name)) {
_del_fs_op(fsp);
if (!_other_fs_ops(type))
break; /* no other non DEL ops */
}
}
else if ((type == FS_ADD) && _count_fs_ops[FS_DEL] && _check_udev(check_udev))
/*
* If udev is running ignore previous DEL operation on added fs_op.
* (No other operations for this device then DEL could be staked here).
*/
dm_list_iterate_safe(fsph, fspht, &_fs_ops) {
fsp = dm_list_item(fsph, struct fs_op_parms);
if ((fsp->type == FS_DEL) &&
!strcmp(lv_name, fsp->lv_name) &&
!strcmp(vg_name, fsp->vg_name)) {
_del_fs_op(fsp);
break; /* no other DEL ops */
}
}
else if ((type == FS_RENAME) && _check_udev(check_udev))
/*
* If udev is running ignore any outstanding operations if renaming it.
*
* Currently RENAME operation happens through 'suspend -> resume'.
* On 'resume' device is added with read_ahead settings, so it
* safe to remove any stacked ADD, RENAME, READ_AHEAD operation
* There cannot be any DEL operation on the renamed device.
*/
dm_list_iterate_safe(fsph, fspht, &_fs_ops) {
fsp = dm_list_item(fsph, struct fs_op_parms);
if (!strcmp(old_lv_name, fsp->lv_name) &&
!strcmp(vg_name, fsp->vg_name))
_del_fs_op(fsp);
}
if (!(fsp = dm_malloc(sizeof(*fsp) + len))) { if (!(fsp = dm_malloc(sizeof(*fsp) + len))) {
log_error("No space to stack fs operation"); log_error("No space to stack fs operation");
return 0; return 0;
@ -333,6 +409,7 @@ static int _stack_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
_store_str(&pos, &fsp->dev, dev); _store_str(&pos, &fsp->dev, dev);
_store_str(&pos, &fsp->old_lv_name, old_lv_name); _store_str(&pos, &fsp->old_lv_name, old_lv_name);
_count_fs_ops[type]++;
dm_list_add(&_fs_ops, &fsp->list); dm_list_add(&_fs_ops, &fsp->list);
return 1; return 1;
@ -347,8 +424,7 @@ static void _pop_fs_ops(void)
fsp = dm_list_item(fsph, struct fs_op_parms); fsp = dm_list_item(fsph, struct fs_op_parms);
_do_fs_op(fsp->type, fsp->dev_dir, fsp->vg_name, fsp->lv_name, _do_fs_op(fsp->type, fsp->dev_dir, fsp->vg_name, fsp->lv_name,
fsp->dev, fsp->old_lv_name, fsp->check_udev); fsp->dev, fsp->old_lv_name, fsp->check_udev);
dm_list_del(&fsp->list); _del_fs_op(fsp);
dm_free(fsp);
} }
} }
@ -423,9 +499,7 @@ void fs_set_cookie(uint32_t cookie)
_fs_cookie = cookie; _fs_cookie = cookie;
} }
#if 0
int fs_has_non_delete_ops(void) int fs_has_non_delete_ops(void)
{ {
return _other_fs_ops(FS_DEL); return _other_fs_ops(FS_DEL);
} }
#endif

View File

@ -725,7 +725,8 @@ typedef enum {
NODE_ADD, NODE_ADD,
NODE_DEL, NODE_DEL,
NODE_RENAME, NODE_RENAME,
NODE_READ_AHEAD NODE_READ_AHEAD,
NUM_NODES
} node_op_t; } node_op_t;
static int _do_node_op(node_op_t type, const char *dev_name, uint32_t major, static int _do_node_op(node_op_t type, const char *dev_name, uint32_t major,
@ -744,12 +745,14 @@ static int _do_node_op(node_op_t type, const char *dev_name, uint32_t major,
case NODE_READ_AHEAD: case NODE_READ_AHEAD:
return _set_dev_node_read_ahead(dev_name, read_ahead, return _set_dev_node_read_ahead(dev_name, read_ahead,
read_ahead_flags); read_ahead_flags);
default:;
} }
return 1; return 1;
} }
static DM_LIST_INIT(_node_ops); static DM_LIST_INIT(_node_ops);
static int _count_node_ops[NUM_NODES];
struct node_op_parms { struct node_op_parms {
struct dm_list list; struct dm_list list;
@ -774,6 +777,31 @@ static void _store_str(char **pos, char **ptr, const char *str)
*pos += strlen(*ptr) + 1; *pos += strlen(*ptr) + 1;
} }
static void _del_node_op(struct node_op_parms *nop)
{
_count_node_ops[nop->type]--;
dm_list_del(&nop->list);
dm_free(nop);
}
/* Check if there is other the type of node operation stacked */
static int _other_node_ops(node_op_t type)
{
int i;
for (i = 0; i < NUM_NODES; i++)
if (type != i && _count_node_ops[i])
return 1;
return 0;
}
/* Check if udev is supposed to create nodes */
static int _check_udev(int check_udev)
{
return check_udev && dm_udev_get_sync_support() && dm_udev_get_checking();
}
static int _stack_node_op(node_op_t type, const char *dev_name, uint32_t major, static int _stack_node_op(node_op_t type, const char *dev_name, uint32_t major,
uint32_t minor, uid_t uid, gid_t gid, mode_t mode, uint32_t minor, uid_t uid, gid_t gid, mode_t mode,
const char *old_name, uint32_t read_ahead, const char *old_name, uint32_t read_ahead,
@ -785,17 +813,47 @@ static int _stack_node_op(node_op_t type, const char *dev_name, uint32_t major,
char *pos; char *pos;
/* /*
* Ignore any outstanding operations on the node if deleting it * Note: check_udev must have valid content
*/ */
if (type == NODE_DEL) { if ((type == NODE_DEL) && _other_node_ops(type))
/*
* Ignore any outstanding operations on the node if deleting it.
*/
dm_list_iterate_safe(noph, nopht, &_node_ops) { dm_list_iterate_safe(noph, nopht, &_node_ops) {
nop = dm_list_item(noph, struct node_op_parms); nop = dm_list_item(noph, struct node_op_parms);
if (!strcmp(dev_name, nop->dev_name)) { if (!strcmp(dev_name, nop->dev_name)) {
dm_list_del(&nop->list); _del_node_op(nop);
dm_free(nop); if (!_other_node_ops(type))
break; /* no other non DEL ops */
} }
} }
} else if ((type == NODE_ADD) && _count_node_ops[NODE_DEL] && _check_udev(check_udev))
/*
* If udev is running ignore previous DEL operation on added node.
* (No other operations for this device then DEL could be staked here).
*/
dm_list_iterate_safe(noph, nopht, &_node_ops) {
nop = dm_list_item(noph, struct node_op_parms);
if ((nop->type == NODE_DEL) &&
!strcmp(dev_name, nop->dev_name)) {
_del_node_op(nop);
break; /* no other DEL ops */
}
}
else if ((type == NODE_RENAME) && _check_udev(check_udev))
/*
* If udev is running ignore any outstanding operations if renaming it.
*
* Currently RENAME operation happens through 'suspend -> resume'.
* On 'resume' device is added with read_ahead settings, so it is
* safe to remove any stacked ADD, RENAME, READ_AHEAD operation
* There cannot be any DEL operation on the renamed device.
*/
dm_list_iterate_safe(noph, nopht, &_node_ops) {
nop = dm_list_item(noph, struct node_op_parms);
if (!strcmp(old_name, nop->dev_name))
_del_node_op(nop);
}
if (!(nop = dm_malloc(sizeof(*nop) + len))) { if (!(nop = dm_malloc(sizeof(*nop) + len))) {
log_error("Insufficient memory to stack mknod operation"); log_error("Insufficient memory to stack mknod operation");
@ -816,6 +874,7 @@ static int _stack_node_op(node_op_t type, const char *dev_name, uint32_t major,
_store_str(&pos, &nop->dev_name, dev_name); _store_str(&pos, &nop->dev_name, dev_name);
_store_str(&pos, &nop->old_name, old_name); _store_str(&pos, &nop->old_name, old_name);
_count_node_ops[type]++;
dm_list_add(&_node_ops, &nop->list); dm_list_add(&_node_ops, &nop->list);
return 1; return 1;
@ -832,8 +891,7 @@ static void _pop_node_ops(void)
nop->uid, nop->gid, nop->mode, nop->old_name, nop->uid, nop->gid, nop->mode, nop->old_name,
nop->read_ahead, nop->read_ahead_flags, nop->read_ahead, nop->read_ahead_flags,
nop->check_udev); nop->check_udev);
dm_list_del(&nop->list); _del_node_op(nop);
dm_free(nop);
} }
} }