/*---------------------------------------------------------------- * 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; }
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; }
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); }
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); }
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); }
/* * 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; }
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); }
/*---------------------------------------------------------------- * 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; }
/*---------------------------------------------------------------- * 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; }
/*---------------------------------------------------------------- * 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; }
/* * 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); }