Example #1
0
/**
 * Invalidate lsid inside ring buffer.
 */
bool invalidate_lsid(struct walb_dev *wdev, u64 lsid)
{
	struct sector_data *zero_sector;
	struct walb_super_sector *super;
	u64 off;
	bool ret;

	ASSERT(lsid != INVALID_LSID);

	zero_sector = sector_alloc(
		wdev->physical_bs, GFP_KERNEL | __GFP_ZERO);
	if (!zero_sector) {
		LOGe("sector allocation failed.\n");
		return false;
	}

	spin_lock(&wdev->lsuper0_lock);
	super = get_super_sector(wdev->lsuper0);
	off = get_offset_of_lsid_2(super, lsid);
	spin_unlock(&wdev->lsuper0_lock);

	ret = sector_io(WRITE, wdev->ldev, off, zero_sector);
	if (!ret) {
		LOGe("sector write failed.\n");
		iocore_set_readonly(wdev);
	}
	sector_free(zero_sector);
	return ret;
}
Example #2
0
/**
 * Check logpack of the given lsid exists.
 *
 * @lsid lsid to check.
 *
 * @return Non-zero if valid, or 0.
 */
int walb_check_lsid_valid(struct walb_dev *wdev, u64 lsid)
{
	struct sector_data *sect;
	struct walb_logpack_header *logh;
	u64 off;

	ASSERT(wdev);

	sect = sector_alloc(wdev->physical_bs, GFP_NOIO);
	if (!sect) {
		LOGe("walb_check_lsid_valid: alloc sector failed.\n");
		goto error0;
	}
	ASSERT(is_same_size_sector(sect, wdev->lsuper0));
	logh = get_logpack_header(sect);

	spin_lock(&wdev->lsuper0_lock);
	off = get_offset_of_lsid_2(get_super_sector(wdev->lsuper0), lsid);
	spin_unlock(&wdev->lsuper0_lock);
	if (!sector_io(READ, wdev->ldev, off, sect)) {
		LOGe("walb_check_lsid_valid: read sector failed.\n");
		goto error1;
	}

	/* Check valid logpack header. */
	if (!is_valid_logpack_header_with_checksum(
			logh, wdev->physical_bs, wdev->log_checksum_salt)) {
		goto error1;
	}

	/* Check lsid. */
	if (logh->logpack_lsid != lsid) {
		goto error1;
	}

	sector_free(sect);
	return 1;

error1:
	sector_free(sect);
error0:
	return 0;
}
Example #3
0
/**
 * Write invalid logpack header.
 * This just fill zero.
 *
 * @fd file descriptor of data device (opened).
 * @super_sect super sector.
 * @lsid lsid to invalidate.
 *
 * RETURN:
 *   true in success, or false.
 */
bool write_invalid_logpack_header(
	int fd, const struct sector_data *super_sect, u64 lsid)
{
	struct sector_data *sect;
	bool ret;
	const struct walb_super_sector *super
		= get_super_sector_const(super_sect);
	u64 off = get_offset_of_lsid_2(super, lsid);

	sect = sector_alloc_zero(super->physical_bs);
	if (!sect) {
		LOGe("Allocate sector failed.\n");
		return false;
	}

	ret = sector_write(fd, off, sect);
	if (!ret) {
		LOGe("Write sector %"PRIu64" for lsid %"PRIu64" failed.\n", off, lsid);
	}
	sector_free(sect);
	return ret;
}
Example #4
0
/**
 * Read logpack data.
 * Padding area will be also read.
 *
 * @fd file descriptor of log device.
 * @super super sector.
 * @logh logpack header.
 * @salt checksum salt.
 * @sect_ary sector array.
 *
 * RETURN:
 *   index of invalid record found at first.
 *   logh->n_records if the whole logpack is valid.
 */
unsigned int read_logpack_data_from_wldev(
	int fd,
	const struct walb_super_sector* super,
	const struct walb_logpack_header* logh, u32 salt,
	struct sector_data_array *sect_ary)
{
	const int lbs = super->logical_bs;
	const int pbs = super->physical_bs;
	int i;
	int total_pb;

	ASSERT(lbs == LOGICAL_BLOCK_SIZE);
	ASSERT_PBS(pbs);

	if (logh->total_io_size > sect_ary->size) {
		LOGe("buffer size is not enough.\n");
		return false;
	}

	total_pb = 0;
	for (i = 0; i < logh->n_records; i++) {
		u64 log_off;
		u32 log_lb, log_pb;

		if (test_bit_u32(LOG_RECORD_DISCARD, &logh->record[i].flags)) {
			continue;
		}
		log_lb = logh->record[i].io_size;
		log_pb = capacity_pb(pbs, log_lb);
		log_off = get_offset_of_lsid_2
			(super, logh->record[i].lsid);
		LOGd_("lsid: %"PRIu64" log_off: %"PRIu64"\n",
			logh->record[i].lsid,
			log_off);

		/* Read data for the log record. */
		if (!sector_array_pread(
				fd, log_off, sect_ary,
				total_pb, log_pb)) {
			LOGe("read sectors failed.\n");
			return i;
		}

		if (test_bit_u32(LOG_RECORD_PADDING, &logh->record[i].flags)) {
			total_pb += log_pb;
			continue;
		}
		/* Confirm checksum */
		u32 csum = sector_array_checksum(
			sect_ary, total_pb * pbs,
			log_lb * lbs, salt);
		if (csum != logh->record[i].checksum) {
			LOGe("log header checksum is invalid. %08x %08x\n",
				csum, logh->record[i].checksum);
			return i;
		}
		total_pb += log_pb;
	}
	ASSERT(i == logh->n_records);
	return logh->n_records;
}
Example #5
0
/**
 * 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;
}