Current implementation suffers from several problems: 1) If someone, e.g. another instance of push-backup tool, mistakenly attempts to freeze ploop while its thawing is in progress, we can end up in double freeze. 2) After initiating thawing, no way to find out it by sysctl or /sys. 3) Handling PLOOP_S_FROZEN bit is not synchronized with ploop STOP/CLEAR ioctls. It's not nice if ploop releases bdev keeping it in frozen state.
The patch fixes the above in straightforward way: more descriptive plo->freeze_state, visible via /sys/block/ploopN/pstate/freeze_state, and special checks in ioctl-s to ensure that freeze/thaw is allowed only on running ploops and that thaw must preceed ploop STOP. https://jira.sw.ru/browse/PSBM-49699 Signed-off-by: Maxim Patlasov <mpatla...@virtuozzo.com> --- drivers/block/ploop/dev.c | 34 ++++++++++++++++++++++++++++++---- drivers/block/ploop/sysfs.c | 6 ++++++ include/linux/ploop/ploop.h | 8 +++++++- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/drivers/block/ploop/dev.c b/drivers/block/ploop/dev.c index 3dc94ca..81d463f 100644 --- a/drivers/block/ploop/dev.c +++ b/drivers/block/ploop/dev.c @@ -3905,6 +3905,13 @@ static int ploop_stop(struct ploop_device * plo, struct block_device *bdev) return -EBUSY; } + if (plo->freeze_state != PLOOP_F_NORMAL) { + if (printk_ratelimit()) + printk(KERN_INFO "stop ploop%d failed (freeze_state=%d)\n", + plo->index, plo->freeze_state); + return -EBUSY; + } + clear_bit(PLOOP_S_PUSH_BACKUP, &plo->state); ploop_pb_stop(plo->pbd, true); @@ -4819,15 +4826,21 @@ static int ploop_freeze(struct ploop_device *plo, struct block_device *bdev) { struct super_block *sb = plo->sb; - if (test_bit(PLOOP_S_FROZEN, &plo->state)) + if (!test_bit(PLOOP_S_RUNNING, &plo->state)) + return -EINVAL; + + if (plo->freeze_state == PLOOP_F_FROZEN) return 0; + if (plo->freeze_state == PLOOP_F_THAWING) + return -EBUSY; + sb = freeze_bdev(bdev); if (sb && IS_ERR(sb)) return PTR_ERR(sb); plo->sb = sb; - set_bit(PLOOP_S_FROZEN, &plo->state); + plo->freeze_state = PLOOP_F_FROZEN; return 0; } @@ -4836,16 +4849,29 @@ static int ploop_thaw(struct ploop_device *plo, struct block_device *bdev) struct super_block *sb = plo->sb; int err; - if (!test_bit(PLOOP_S_FROZEN, &plo->state)) + if (!test_bit(PLOOP_S_RUNNING, &plo->state)) + return -EINVAL; + + if (plo->freeze_state == PLOOP_F_NORMAL) return 0; + if (plo->freeze_state == PLOOP_F_THAWING) + return -EBUSY; + plo->sb = NULL; - clear_bit(PLOOP_S_FROZEN, &plo->state); + plo->freeze_state = PLOOP_F_THAWING; mutex_unlock(&plo->ctl_mutex); err = thaw_bdev(bdev, sb); mutex_lock(&plo->ctl_mutex); + BUG_ON(plo->freeze_state != PLOOP_F_THAWING); + + if (!err) + plo->freeze_state = PLOOP_F_NORMAL; + else + plo->freeze_state = PLOOP_F_FROZEN; + return err; } diff --git a/drivers/block/ploop/sysfs.c b/drivers/block/ploop/sysfs.c index d6dcc83..71b2a20 100644 --- a/drivers/block/ploop/sysfs.c +++ b/drivers/block/ploop/sysfs.c @@ -425,6 +425,11 @@ static ssize_t print_push_backup_uuid(struct ploop_device * plo, char * page) return snprintf(page, PAGE_SIZE, "%pUB\n", uuid); } +static u32 show_freeze_state(struct ploop_device * plo) +{ + return plo->freeze_state; +} + #define _TUNE_U32(_name) \ static u32 show_##_name(struct ploop_device * plo) \ { \ @@ -507,6 +512,7 @@ static struct attribute *state_attributes[] = { _A3(cookie), _A3(push_backup_uuid), _A(open_count), + _A(freeze_state), NULL }; diff --git a/include/linux/ploop/ploop.h b/include/linux/ploop/ploop.h index 7864edf..8ab4477 100644 --- a/include/linux/ploop/ploop.h +++ b/include/linux/ploop/ploop.h @@ -61,7 +61,12 @@ enum { (for minor mgmt only) */ PLOOP_S_ONCE, /* An event (e.g. printk once) happened */ PLOOP_S_PUSH_BACKUP, /* Push_backup is in progress */ - PLOOP_S_FROZEN /* Frozen PLOOP_IOC_FREEZE */ +}; + +enum { + PLOOP_F_NORMAL, /* Default: not yet freezed or unfrozen */ + PLOOP_F_FROZEN, /* Frozen PLOOP_IOC_FREEZE */ + PLOOP_F_THAWING, /* thaw_bdev is in progress */ }; struct ploop_snapdata @@ -411,6 +416,7 @@ struct ploop_device struct request_queue *queue; struct task_struct *thread; struct super_block *sb; + int freeze_state; struct rb_node link; /* someone who wants to quiesce state-machine waits _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel