/** * Melt a frozen device. * * @wdev walb dev. * @ctl ioctl data. * RETURN: * 0 in success, or -EFAULT. */ static int ioctl_wdev_melt(struct walb_dev *wdev, struct walb_ctl *ctl) { ASSERT(ctl->command == WALB_IOCTL_MELT); LOGn("WALB_IOCTL_MELT\n"); cancel_melt_work(wdev); if (melt_if_frozen(wdev, true)) { return 0; } return -EFAULT; }
/** * Freeze a walb device. * Currently write IOs will be frozen but read IOs will not. * * @wdev walb dev. * @ctl ioctl data. * RETURN: * 0 in success, or -EFAULT. */ static int ioctl_wdev_freeze(struct walb_dev *wdev, struct walb_ctl *ctl) { u32 timeout_sec; ASSERT(ctl->command == WALB_IOCTL_FREEZE); LOGn("WALB_IOCTL_FREEZE\n"); /* Clip timeout value. */ timeout_sec = ctl->val_u32; if (timeout_sec > 86400) { timeout_sec = 86400; LOGn("Freeze timeout has been cut to %"PRIu32" seconds.\n", timeout_sec); } cancel_melt_work(wdev); if (freeze_if_melted(wdev, timeout_sec)) { return 0; } return -EFAULT; }
/** * Melt a device if frozen. * * RETURN: * true in success, or false (due to race condition). */ bool melt_if_frozen( struct walb_dev *wdev, bool restarts_checkpointing) { unsigned int minor; ASSERT(wdev); minor = MINOR(wdev->devt); cancel_melt_work(wdev); /* Melt the device if required. */ mutex_lock(&wdev->freeze_lock); switch (wdev->freeze_state) { case FRZ_MELTED: /* Do nothing. */ LOGn("Already melted minor %u\n", minor); break; case FRZ_FREEZED: /* Melt. */ LOGn("Melt walb device minor %u.\n", minor); if (restarts_checkpointing) { start_checkpointing(&wdev->cpd); } iocore_melt(wdev); wdev->freeze_state = FRZ_MELTED; break; case FRZ_FREEZED_WITH_TIMEOUT: /* Race condition. */ LOGe("Race condition occurred.\n"); mutex_unlock(&wdev->freeze_lock); return false; default: BUG(); } ASSERT(wdev->freeze_state == FRZ_MELTED); mutex_unlock(&wdev->freeze_lock); return true; }