static int __init iostash_init(void)
{
    int ret = -1, i;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
	ERR("Kernel version < 2.6.28 not supported.");
	return -ENOENT;
#endif
	DBG("++ iostash_init() ++\n");

	memset(&gctx, 0, sizeof(gctx));
	do {
		gctx.io_pool = KMEM_CACHE(iostash_bio, 0);
		if (!gctx.io_pool) {
			ERR("iostash_init: KMEM_CACHE() failed\n");
			break;
		}

		gctx.io_client = dm_io_client_create();
		if (IS_ERR(gctx.io_client)) {
			ERR("iostash_init: dm_io_client() failed\n");
			break;
		}

		gctx.sce = sce_create();
		if (!gctx.sce) {
			ERR("iostash_init: sce_create() failed\n");
			break;
		}

		gctx.pdm = pdm_create(gctx.sce, poptask_read, poptask_write);

		if (_init_iostash_kobjects()) {
		    ERR("KOBJECT INIT FAILED!");
		    _destroy_iostash_kobjects();
		}

		mutex_init(&gctx.ctl_mtx);

		for (i = 0; i < IOSTASH_MAXHDD_BCKTS; ++i)
		    INIT_LIST_HEAD(&gctx.hddtbl.bucket[i]);

		for (i = 0; i < IOSTASH_MAXSSD_BCKTS; ++i)
		    INIT_LIST_HEAD(&gctx.ssdtbl.bucket[i]);

		ret = 0;

	} while (0);

	if (ret) {
		_free_resource();
	}

	DBG("-- iostash_init() returns = %d --\n", ret);
	return ret;
}
Beispiel #2
0
static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
			      unsigned int argc, char **argv,
			      struct dm_dev *dev)
{
	enum sync sync = DEFAULTSYNC;

	struct log_c *lc;
	uint32_t region_size;
	unsigned int region_count;
	size_t bitset_size, buf_size;
	int r;
	char dummy;

	if (argc < 1 || argc > 2) {
		DMWARN("wrong number of arguments to dirty region log");
		return -EINVAL;
	}

	if (argc > 1) {
		if (!strcmp(argv[1], "sync"))
			sync = FORCESYNC;
		else if (!strcmp(argv[1], "nosync"))
			sync = NOSYNC;
		else {
			DMWARN("unrecognised sync argument to "
			       "dirty region log: %s", argv[1]);
			return -EINVAL;
		}
	}

	if (sscanf(argv[0], "%u%c", &region_size, &dummy) != 1 ||
	    !_check_region_size(ti, region_size)) {
		DMWARN("invalid region size %s", argv[0]);
		return -EINVAL;
	}

	region_count = dm_sector_div_up(ti->len, region_size);

	lc = kmalloc(sizeof(*lc), GFP_KERNEL);
	if (!lc) {
		DMWARN("couldn't allocate core log");
		return -ENOMEM;
	}

	lc->ti = ti;
	lc->touched_dirtied = 0;
	lc->touched_cleaned = 0;
	lc->flush_failed = 0;
	lc->region_size = region_size;
	lc->region_count = region_count;
	lc->sync = sync;

	/*
	 * Work out how many "unsigned long"s we need to hold the bitset.
	 */
	bitset_size = dm_round_up(region_count,
				  sizeof(*lc->clean_bits) << BYTE_SHIFT);
	bitset_size >>= BYTE_SHIFT;

	lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits);

	/*
	 * Disk log?
	 */
	if (!dev) {
		lc->clean_bits = vmalloc(bitset_size);
		if (!lc->clean_bits) {
			DMWARN("couldn't allocate clean bitset");
			kfree(lc);
			return -ENOMEM;
		}
		lc->disk_header = NULL;
	} else {
		lc->log_dev = dev;
		lc->log_dev_failed = 0;
		lc->log_dev_flush_failed = 0;
		lc->header_location.bdev = lc->log_dev->bdev;
		lc->header_location.sector = 0;

		/*
		 * Buffer holds both header and bitset.
		 */
		buf_size =
		    dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + bitset_size,
				bdev_logical_block_size(lc->header_location.
							    bdev));

		if (buf_size > i_size_read(dev->bdev->bd_inode)) {
			DMWARN("log device %s too small: need %llu bytes",
				dev->name, (unsigned long long)buf_size);
			kfree(lc);
			return -EINVAL;
		}

		lc->header_location.count = buf_size >> SECTOR_SHIFT;

		lc->io_req.mem.type = DM_IO_VMA;
		lc->io_req.notify.fn = NULL;
		lc->io_req.client = dm_io_client_create();
		if (IS_ERR(lc->io_req.client)) {
			r = PTR_ERR(lc->io_req.client);
			DMWARN("couldn't allocate disk io client");
			kfree(lc);
			return r;
		}

		lc->disk_header = vmalloc(buf_size);
		if (!lc->disk_header) {
			DMWARN("couldn't allocate disk log buffer");
			dm_io_client_destroy(lc->io_req.client);
			kfree(lc);
			return -ENOMEM;
		}

		lc->io_req.mem.ptr.vma = lc->disk_header;
		lc->clean_bits = (void *)lc->disk_header +
				 (LOG_OFFSET << SECTOR_SHIFT);
	}

	memset(lc->clean_bits, -1, bitset_size);

	lc->sync_bits = vmalloc(bitset_size);
	if (!lc->sync_bits) {
		DMWARN("couldn't allocate sync bitset");
		if (!dev)
			vfree(lc->clean_bits);
		else
			dm_io_client_destroy(lc->io_req.client);
		vfree(lc->disk_header);
		kfree(lc);
		return -ENOMEM;
	}
	memset(lc->sync_bits, (sync == NOSYNC) ? -1 : 0, bitset_size);
	lc->sync_count = (sync == NOSYNC) ? region_count : 0;

	lc->recovering_bits = vzalloc(bitset_size);
	if (!lc->recovering_bits) {
		DMWARN("couldn't allocate sync bitset");
		vfree(lc->sync_bits);
		if (!dev)
			vfree(lc->clean_bits);
		else
			dm_io_client_destroy(lc->io_req.client);
		vfree(lc->disk_header);
		kfree(lc);
		return -ENOMEM;
	}
	lc->sync_search = 0;
	log->context = lc;

	return 0;
}
Beispiel #3
0
/*----------------------------------------------------------------
 * disk log constructor/destructor
 *
 * argv contains 2 - 4 arguments:
 *	 <log_device> <region_size> [[no]sync] [block_on_error]
 *--------------------------------------------------------------*/
static int disk_ctr(struct dirty_log *log, struct dm_target *ti,
		    unsigned int argc, char **argv)
{
	int r;
	size_t size, bitset_size;
	struct log_c *lc;
	struct dm_dev *dev;
	uint32_t *clean_bits;

	if (argc < 2 || argc > 4) {
		DMWARN("wrong number of arguments to disk mirror log");
		return -EINVAL;
	}

	r = dm_get_device(ti, argv[0], 0, 0 /* FIXME */,
			  FMODE_READ | FMODE_WRITE, &dev);
	if (r)
		return r;

	r = core_ctr(log, ti, argc - 1, argv + 1);
	if (r) {
		dm_put_device(ti, dev);
		return r;
	}

	lc = (struct log_c *) log->context;
	lc->log_dev = dev;
	lc->log_dev_failed = 0;

	/* setup the disk header fields */
	lc->header_location.bdev = lc->log_dev->bdev;
	lc->header_location.sector = 0;

	/* Include both the header and the bitset in one buffer. */
	bitset_size = lc->bitset_uint32_count * sizeof(uint32_t);
	size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + bitset_size,
			   ti->limits.hardsect_size);

	if (size > dev->bdev->bd_inode->i_size) {
		DMWARN("log device %s too small: need %llu bytes",
		       dev->name, (unsigned long long)size);
		r = -EINVAL;
		goto bad;
	}

	lc->header_location.count = size >> SECTOR_SHIFT;

	lc->disk_header = vmalloc(size);
	if (!lc->disk_header) {
		r = -ENOMEM;
		goto bad;
	}

	/*
	 * Deallocate the clean_bits buffer that was allocated in core_ctr()
	 * and point it at the appropriate place in the disk_header buffer.
	 */
	clean_bits = lc->clean_bits;
	lc->clean_bits = (void *)lc->disk_header + (LOG_OFFSET << SECTOR_SHIFT);
	memcpy(lc->clean_bits, clean_bits, bitset_size);
	vfree(clean_bits);

	lc->io_req.mem.type = DM_IO_VMA;
	lc->io_req.client = dm_io_client_create(dm_div_up(size, PAGE_SIZE));
	if (IS_ERR(lc->io_req.client)) {
		r = PTR_ERR(lc->io_req.client);
		DMWARN("couldn't allocate disk io client");
		vfree(lc->disk_header);
		goto bad;
	}
	return 0;

 bad:
	dm_put_device(ti, lc->log_dev);
	core_dtr(log);
	return r;
}
Beispiel #4
0
/*
 * Construct a striped mapping.
 * <number of stripes> <chunk size> [<dev_path> <offset>]+
 */
static int vm_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
	struct vm_c *vc;
	sector_t width, tmp_len;
	uint32_t vms;
	uint32_t chunk_size;
	int r;
	unsigned long long i;

	if (argc < 2) {
		ti->error = "Not enough arguments";
		return -EINVAL;
	}

	if (kstrtouint(argv[0], 10, &vms) || !vms) {
		ti->error = "Invalid stripe count";
		return -EINVAL;
	}

	if (kstrtouint(argv[1], 10, &chunk_size) || !chunk_size) {
		ti->error = "Invalid chunk_size";
		return -EINVAL;
	}

	width = ti->len;
	if (sector_div(width, vms)) {
		ti->error = "Target length not divisible by "
		    "number of stripes";
		return -EINVAL;
	}

	tmp_len = width;
	if (sector_div(tmp_len, chunk_size)) {
		ti->error = "Target length not divisible by "
		    "chunk size";
		return -EINVAL;
	}

	/*
	 * Do we have enough arguments for that many stripes ?
	 */
	if (argc != (2 + 2 * vms)) {
		ti->error = "Not enough destinations "
			"specified";
		return -EINVAL;
	}

	vc = alloc_context(vms);
	if (!vc) {
		ti->error = "Memory allocation for striped context "
		    "failed";
		return -ENOMEM;
	}

	INIT_WORK(&vc->trigger_event, trigger_event);

	/* Set pointer to dm target; used in trigger_event */
	vc->ti = ti;
	vc->vms = vms;
	vc->vm_width = width;

	if (vms & (vms - 1))
		vc->vms_shift = -1;
	else
		vc->vms_shift = __ffs(vms);

	r = dm_set_target_max_io_len(ti, chunk_size);
	if (r) {
		kfree(vc);
		return r;
	}

	ti->num_flush_bios = vms;
	ti->num_discard_bios = vms;
	ti->num_write_same_bios = vms;

	vc->chunk_size = chunk_size;
	if (chunk_size & (chunk_size - 1))
		vc->chunk_size_shift = -1;
	else
		vc->chunk_size_shift = __ffs(chunk_size);

	/*
	 * Get the stripe destinations.
	 */
	for (i = 0; i < vms; i++) {
		argv += 2;

		r = get_vm(ti, vc, i, argv);
		if (r < 0) {
			ti->error = "Couldn't parse stripe destination";
			while (i--)
				dm_put_device(ti, vc->vm[i].dev);
			kfree(vc);
			return r;
		}
		atomic_set(&(vc->vm[i].error_count), 0);
	}

	/*volume manager initialize*/
	vc->wp = 0;//////current 0 is NVMe
	//vc->wp = 1;
	vc->ws = kmalloc(sizeof(unsigned long long) * vc->vms, GFP_KERNEL);
	for(i = 0; i<vc->vms; i++)
		vc->ws[i] = 0;
	vc->gp_list = kmalloc(sizeof(char) * vc->vms, GFP_KERNEL);
	vc->num_gp = 0;
	vc->io_client = dm_io_client_create();
	vc->gs = NULL;
	vc->overload = 0;
	for(i=0; i<vc->vms; i++)
		vc->gp_list[i] = Clean_Weight;//0 is clean
	{
		unsigned long long tem, disk_size;
		
		tem = 0;
		for(i = 0; i<vms; i++){
			struct block_device *cur_bdev = vc->vm[i].dev->bdev;
			vc->vm[i].end_sector = i_size_read(cur_bdev->bd_inode)>>9;//unit of sector
			printk("vm%llu start_sector %llu, end_sector %llu, target_offset %llu\n",
					i, (unsigned long long) vc->vm[i].physical_start, (unsigned long long) vc->vm[i].end_sector, (unsigned long long)dm_target_offset(ti, vc->ws[i]));
			disk_size = vc->vm[i].end_sector * 512;
			do_div(disk_size, (unsigned long long) vc->vm[i].dev->bdev->bd_block_size);
			tem += disk_size;
		}
		vc->num_entry = tem;//num entry is blk num
	}
	printk("num entry is %llu, node size is %lu, req mem is %llu\n", vc->num_entry, sizeof(struct flag_nodes), sizeof(struct flag_nodes) * vc->num_entry);
	
	//flag set initialize
	vc->fs = (struct flag_set *) kmalloc(sizeof(struct flag_set), GFP_KERNEL);
	vc->fs->node_buf = kmem_cache_create("dirty_data_buf", sizeof(struct flag_nodes),
			0, (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD), NULL);

	vc->fs->table = (struct flag_nodes **)vmalloc(sizeof(struct flag_nodes*) * vc->num_entry);
	for(i=0; i<vc->num_entry; i++){
		//vc->fs->table[i] = NULL;//late alloc code
		vc->fs->table[i] = kmem_cache_alloc(vc->fs->node_buf, GFP_KERNEL);//pre alloc start
		vc->fs->table[i]->msector = -1;
		vc->fs->table[i]->wp = -1;//pre alloc end
	}
	vc->num_map_block = 0;//vc->num_entry * sizeof(struct flag_nodes) / 4096;
	//vc->ws[0] += vc->num_map_block;

	vc->fs->reverse_table = vmalloc(sizeof(struct reverse_nodes*) * vc->vms);
	vc->d_num = kmalloc(sizeof(unsigned long long) * vc->vms, GFP_KERNEL);
	for(i=0; i<vc->vms; i++){
		unsigned long long j;
		unsigned long long r_table_size = (vc->vm[i].end_sector + 7);
		unsigned long long phy_sect = vc->vm[i].physical_start;
		do_div(phy_sect, 8);
		do_div(r_table_size, 8);
		printk("r_table_size = %llu\n", r_table_size);
		vc->vm[i].num_dirty = r_table_size - phy_sect;
		vc->d_num[i] = vc->vm[i].num_dirty;
		vc->fs->reverse_table[i] = vmalloc(sizeof(struct reverse_nodes) * r_table_size);
		for(j=0; j<r_table_size; j++){
			vc->fs->reverse_table[i][j].index = -1;
			vc->fs->reverse_table[i][j].dirty = 1;
			vc->fs->reverse_table[i][j].size = -1;
		}
		//printk("%u's first ptr is %p, final ptr is %p\n", i, &(vc->fs->reverse_table[i][0]), &(vc->fs->reverse_table[i][j]));
	}

	for(i=0; i<vc->vms; i++){
		unsigned int minor = atom(vc->vm[i].dev->name);
		unsigned int major = atoj(vc->vm[i].dev->name);

		printk("dev name is %s\t", vc->vm[i].dev->name);
		if(major != 2600) vc->vm[i].main_dev = minor >> minor_shift;
		else vc->vm[i].main_dev = minor - 1;
		vc->vm[i].maj_dev = major;
		printk("main %u, maj %u\n", vc->vm[i].main_dev, vc->vm[i].maj_dev);
	}