Esempio n. 1
0
/*----------------------------------------------------------------
 * disk log constructor/destructor
 *
 * argv contains log_device region_size followed optionally by [no]sync
 *--------------------------------------------------------------*/
static int disk_ctr(struct dirty_log *log, struct dm_target *ti,
		    unsigned int argc, char **argv)
{
	int r;
	size_t size;
	struct log_c *lc;
	struct dm_dev *dev;

	if (argc < 2 || argc > 3) {
		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;

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

	/*
	 * We can't read less than this amount, even though we'll
	 * not be using most of this space.
	 */
	lc->disk_header = vmalloc(1 << SECTOR_SHIFT);
	if (!lc->disk_header)
		goto bad;

	/* setup the disk bitset fields */
	lc->bits_location.bdev = lc->log_dev->bdev;
	lc->bits_location.sector = LOG_OFFSET;

	size = dm_round_up(lc->bitset_uint32_count * sizeof(uint32_t),
			   1 << SECTOR_SHIFT);
	lc->bits_location.count = size >> SECTOR_SHIFT;
	lc->disk_bits = vmalloc(size);
	if (!lc->disk_bits) {
		vfree(lc->disk_header);
		goto bad;
	}
	return 0;

 bad:
	dm_put_device(ti, lc->log_dev);
	core_dtr(log);
	return -ENOMEM;
}
Esempio n. 2
0
static void userspace_dtr(struct dm_dirty_log *log)
{
	struct log_c *lc = log->context;

	if (lc->integrated_flush) {
		/* flush workqueue */
		if (atomic_read(&lc->sched_flush))
			flush_delayed_work(&lc->flush_log_work);

		destroy_workqueue(lc->dmlog_wq);
	}

	(void) dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_DTR,
				    NULL, 0, NULL, NULL);

	if (lc->log_dev)
		dm_put_device(lc->ti, lc->log_dev);

	mempool_destroy(lc->flush_entry_pool);

	kfree(lc->usr_argv_str);
	kfree(lc);

	return;
}
/**ltl
 * 功能: 将目标设备加入到列表中
 * 参数: t	->映射表
 *		ti	->映射目标
 *		path	->映射目标<major:minor>
 * 		start-> 映射目标相对低层设备的起始偏移量(类似磁盘分区的起始地址)
 *		len	-> 此目标设备在dm设备的长度
 *		mode	-> rw
 *		result-> 底层设备对象
 * 返回值:
 * 说明:
 */
static int __table_get_device(struct dm_table *t, struct dm_target *ti,
			      const char *path, sector_t start, sector_t len,
			      int mode, struct dm_dev **result)
{
	int r;
	dev_t dev;
	struct dm_dev *dd;
	unsigned int major, minor;

	BUG_ON(!t);
	/* 获取主设备号和次设备号 */
	if (sscanf(path, "%u:%u", &major, &minor) == 2) {
		/* Extract the major/minor numbers */
		dev = MKDEV(major, minor);
		if (MAJOR(dev) != major || MINOR(dev) != minor)
			return -EOVERFLOW;
	} else {
		/* convert the path to a device */
		if ((r = lookup_device(path, &dev))) /* 根据设备路径/dev/sdb获取<major:minor> */
			return r;
	}
	/* 在列表中查找映射目标 */
	dd = find_device(&t->devices, dev);
	if (!dd) {
		dd = kmalloc(sizeof(*dd), GFP_KERNEL);
		if (!dd)
			return -ENOMEM;

		dd->mode = mode;
		dd->bdev = NULL;
		/* 打开设备 */
		if ((r = open_dev(dd, dev, t->md))) {
			kfree(dd);
			return r;
		}

		format_dev_t(dd->name, dev); /* 主设备号次设备号 */

		atomic_set(&dd->count, 0);
		/* 将目标设备插入到映射表中 */
		list_add(&dd->list, &t->devices);

	} else if (dd->mode != (mode | dd->mode)) {
		r = upgrade_mode(dd, mode, t->md);
		if (r)
			return r;
	}
	atomic_inc(&dd->count);
	/* 检查区域是否超过设备 */
	if (!check_device_area(dd, start, len)) {
		DMWARN("device %s too small for target", path);
		dm_put_device(ti, dd);
		return -EINVAL;
	}

	*result = dd;

	return 0;
}
Esempio n. 4
0
static void disk_dtr(struct dirty_log *log)
{
	struct log_c *lc = (struct log_c *) log->context;

	dm_put_device(lc->ti, lc->log_dev);
	vfree(lc->disk_header);
	destroy_log_context(lc);
}
Esempio n. 5
0
static void disk_dtr(struct dirty_log *log)
{
	struct log_c *lc = (struct log_c *) log->context;
	dm_put_device(lc->ti, lc->log_dev);
	vfree(lc->disk_header);
	vfree(lc->disk_bits);
	core_dtr(log);
}
Esempio n. 6
0
static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
{
	struct pgpath *pgpath, *tmp;

	list_for_each_entry_safe(pgpath, tmp, pgpaths, list) {
		list_del(&pgpath->list);
		dm_put_device(ti, pgpath->path.dev);
		free_pgpath(pgpath);
	}
Esempio n. 7
0
/*
 * Add a device to the list, or just increment the usage count if
 * it's already present.
 */
static int __table_get_device(struct dm_table *t, struct dm_target *ti,
			      const char *path, sector_t start, sector_t len,
			      int mode, struct dm_dev **result)
{
	int r;
	dev_t dev;
	struct dm_dev *dd;
	unsigned int major, minor;

	if (!t)
		BUG();

	if (sscanf(path, "%u:%u", &major, &minor) == 2) {
		/* Extract the major/minor numbers */
		dev = MKDEV(major, minor);
		if (MAJOR(dev) != major || MINOR(dev) != minor)
			return -EOVERFLOW;
	} else {
		/* convert the path to a device */
		if ((r = lookup_device(path, &dev)))
			return r;
	}

	dd = find_device(&t->devices, dev);
	if (!dd) {
		dd = kmalloc(sizeof(*dd), GFP_KERNEL);
		if (!dd)
			return -ENOMEM;

		dd->mode = mode;
		dd->bdev = NULL;

		if ((r = open_dev(dd, dev))) {
			kfree(dd);
			return r;
		}

		atomic_set(&dd->count, 0);
		list_add(&dd->list, &t->devices);

	} else if (dd->mode != (mode | dd->mode)) {
		r = upgrade_mode(dd, mode);
		if (r)
			return r;
	}
	atomic_inc(&dd->count);

	if (!check_device_area(dd, start, len)) {
		DMWARN("device %s too small for target", path);
		dm_put_device(ti, dd);
		return -EINVAL;
	}

	*result = dd;

	return 0;
}
Esempio n. 8
0
static void disk_dtr(struct dirty_log *log)
{
	struct log_c *lc = (struct log_c *) log->context;
	dm_put_device(lc->ti, lc->log_dev);
	dm_io_client_destroy(lc->io_req.client);
	vfree(lc->disk_header);
	lc->clean_bits = NULL;
	core_dtr(log);
}
static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
{
	struct pgpath *pgpath, *tmp;
	struct multipath *m = ti->private;

	list_for_each_entry_safe(pgpath, tmp, pgpaths, list) {
		list_del(&pgpath->list);
		if (m->hw_handler_name)
			scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev));
		dm_put_device(ti, pgpath->path.dev);
		free_pgpath(pgpath);
	}
static void userspace_dtr(struct dm_dirty_log *log)
{
	struct log_c *lc = log->context;

	(void) dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_DTR,
				 NULL, 0,
				 NULL, NULL);

	if (lc->log_dev)
		dm_put_device(lc->ti, lc->log_dev);

	kfree(lc->usr_argv_str);
	kfree(lc);

	return;
}
static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
{
	unsigned long flags;
	struct pgpath *pgpath, *tmp;
	struct multipath *m = ti->private;

	list_for_each_entry_safe(pgpath, tmp, pgpaths, list) {
		list_del(&pgpath->list);
		if (m->hw_handler_name)
			scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev));
		dm_put_device(ti, pgpath->path.dev);
		spin_lock_irqsave(&m->lock, flags);
		if (m->pgpath_to_activate == pgpath)
			m->pgpath_to_activate = NULL;
		spin_unlock_irqrestore(&m->lock, flags);
		free_pgpath(pgpath);
	}
Esempio n. 12
0
/*----------------------------------------------------------------
 * disk log constructor/destructor
 *
 * argv contains log_device region_size followed optionally by [no]sync
 *--------------------------------------------------------------*/
static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti,
		    unsigned int argc, char **argv)
{
	int r;
	struct dm_dev *dev;

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

	r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &dev);
	if (r)
		return r;

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

	return 0;
}
Esempio n. 13
0
/*----------------------------------------------------------------
 * disk log constructor/destructor
 *
 * argv contains log_device region_size followed optionally by [no]sync
 *--------------------------------------------------------------*/
static int disk_ctr(struct dirty_log *log, struct dm_target *ti,
		    unsigned int argc, char **argv)
{
	int r;
	struct dm_dev *dev;

	if (argc < 2 || argc > 3) {
		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 = create_log_context(log, ti, argc - 1, argv + 1, dev);
	if (r) {
		dm_put_device(ti, dev);
		return r;
	}

	return 0;
}
Esempio n. 14
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;
}
Esempio n. 15
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);
	}