/** * Set oldest_lsid. * * @wdev walb dev. * @ctl ioctl data. * RETURN: * 0 in success, or -EFAULT. */ static int ioctl_wdev_set_oldest_lsid(struct walb_dev *wdev, struct walb_ctl *ctl) { u64 lsid, oldest_lsid, written_lsid; LOGn("WALB_IOCTL_SET_OLDEST_LSID_SET\n"); lsid = ctl->val_u64; spin_lock(&wdev->lsid_lock); written_lsid = wdev->lsids.written; oldest_lsid = wdev->lsids.oldest; spin_unlock(&wdev->lsid_lock); if (!(lsid == written_lsid || (oldest_lsid <= lsid && lsid < written_lsid && walb_check_lsid_valid(wdev, lsid)))) { LOGe("lsid %"PRIu64" is not valid.\n", lsid); LOGe("You shoud specify valid logpack header lsid" " (oldest_lsid (%"PRIu64") <= lsid <= written_lsid (%"PRIu64").\n", oldest_lsid, written_lsid); return -EFAULT; } spin_lock(&wdev->lsid_lock); wdev->lsids.oldest = lsid; spin_unlock(&wdev->lsid_lock); if (!walb_sync_super_block(wdev)) { LOGe("sync super block failed.\n"); return -EFAULT; } return 0; }
/** * Resize walb device. * * @wdev walb dev. * @ctl ioctl data. * RETURN: * 0 in success, or -EFAULT. */ static int ioctl_wdev_resize(struct walb_dev *wdev, struct walb_ctl *ctl) { u64 ddev_size; u64 new_size; u64 old_size; LOGn("WALB_IOCTL_RESIZE.\n"); ASSERT(ctl->command == WALB_IOCTL_RESIZE); old_size = get_capacity(wdev->gd); new_size = ctl->val_u64; ddev_size = wdev->ddev->bd_part->nr_sects; if (new_size == 0) { new_size = ddev_size; } if (new_size < old_size) { LOGe("Shrink size from %"PRIu64" to %"PRIu64" is not supported.\n", old_size, new_size); return -EFAULT; } if (new_size > ddev_size) { LOGe("new_size %"PRIu64" > data device capacity %"PRIu64".\n", new_size, ddev_size); return -EFAULT; } if (new_size == old_size) { LOGn("No need to resize.\n"); return 0; } spin_lock(&wdev->size_lock); wdev->size = new_size; wdev->ddev_size = ddev_size; spin_unlock(&wdev->size_lock); if (!resize_disk(wdev->gd, new_size)) { return -EFAULT; } /* Sync super block for super->device_size */ if (!walb_sync_super_block(wdev)) { LOGe("superblock sync failed.\n"); return -EFAULT; } return 0; }
/** * Take a checkpoint immediately. * * @cpd checkpoint data. * * RETURN: * ture in success, or false. */ bool take_checkpoint(struct checkpoint_data *cpd) { bool skip; struct walb_dev *wdev; ASSERT(cpd); wdev = get_wdev_from_checkpoint_data(cpd); ASSERT(wdev); /* Check the need of writing superblock. */ spin_lock(&wdev->lsid_lock); skip = wdev->lsids.written == wdev->lsids.prev_written; spin_unlock(&wdev->lsid_lock); if (skip) { WLOG_(wdev, "skip superblock sync.\n"); return true; } /* Write and flush super block at log device. */ return walb_sync_super_block(wdev); }
/** * Clear log and detect resize of log device. * * @wdev walb dev. * @ctl ioctl data. * RETURN: * 0 in success, or -EFAULT. */ static int ioctl_wdev_clear_log(struct walb_dev *wdev, struct walb_ctl *ctl) { u64 new_ldev_size, old_ldev_size; u8 new_uuid[UUID_SIZE], old_uuid[UUID_SIZE]; unsigned int pbs = wdev->physical_bs; bool is_grown = false; struct walb_super_sector *super; u64 lsid0_off; struct lsid_set lsids; u64 old_ring_buffer_size; u32 new_salt; ASSERT(ctl->command == WALB_IOCTL_CLEAR_LOG); LOGn("WALB_IOCTL_CLEAR_LOG.\n"); /* Freeze iocore and checkpointing. */ iocore_freeze(wdev); stop_checkpointing(&wdev->cpd); /* Get old/new log device size. */ old_ldev_size = wdev->ldev_size; new_ldev_size = wdev->ldev->bd_part->nr_sects; if (old_ldev_size > new_ldev_size) { LOGe("Log device shrink not supported.\n"); goto error0; } /* Backup variables. */ old_ring_buffer_size = wdev->ring_buffer_size; backup_lsid_set(wdev, &lsids); /* Initialize lsid(s). */ spin_lock(&wdev->lsid_lock); wdev->lsids.latest = 0; wdev->lsids.flush = 0; wdev->lsids.completed = 0; wdev->lsids.permanent = 0; wdev->lsids.written = 0; wdev->lsids.prev_written = 0; wdev->lsids.oldest = 0; spin_unlock(&wdev->lsid_lock); /* Grow the walblog device. */ if (old_ldev_size < new_ldev_size) { LOGn("Detect log device size change.\n"); /* Grow the disk. */ is_grown = true; if (!resize_disk(wdev->log_gd, new_ldev_size)) { LOGe("grow disk failed.\n"); iocore_set_readonly(wdev); goto error1; } LOGn("Grown log device size from %"PRIu64" to %"PRIu64".\n", old_ldev_size, new_ldev_size); wdev->ldev_size = new_ldev_size; /* Recalculate ring buffer size. */ wdev->ring_buffer_size = addr_pb(pbs, new_ldev_size) - get_ring_buffer_offset(pbs); } /* Generate new uuid and salt. */ get_random_bytes(new_uuid, 16); get_random_bytes(&new_salt, sizeof(new_salt)); wdev->log_checksum_salt = new_salt; /* Update superblock image. */ spin_lock(&wdev->lsuper0_lock); super = get_super_sector(wdev->lsuper0); memcpy(old_uuid, super->uuid, UUID_SIZE); memcpy(super->uuid, new_uuid, UUID_SIZE); super->ring_buffer_size = wdev->ring_buffer_size; super->log_checksum_salt = new_salt; /* super->metadata_size; */ lsid0_off = get_offset_of_lsid_2(super, 0); spin_unlock(&wdev->lsuper0_lock); /* Sync super sector. */ if (!walb_sync_super_block(wdev)) { LOGe("sync superblock failed.\n"); iocore_set_readonly(wdev); goto error2; } /* Invalidate first logpack */ if (!invalidate_lsid(wdev, 0)) { LOGe("invalidate lsid 0 failed.\n"); iocore_set_readonly(wdev); goto error2; } /* Clear log overflow. */ iocore_clear_log_overflow(wdev); /* Melt iocore and checkpointing. */ start_checkpointing(&wdev->cpd); iocore_melt(wdev); return 0; error2: restore_lsid_set(wdev, &lsids); wdev->ring_buffer_size = old_ring_buffer_size; #if 0 wdev->ldev_size = old_ldev_size; if (!resize_disk(wdev->log_gd, old_ldev_size)) { LOGe("resize_disk to shrink failed.\n"); } #endif error1: start_checkpointing(&wdev->cpd); iocore_melt(wdev); error0: return -EFAULT; }