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; }
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", ®ion_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; }
/*---------------------------------------------------------------- * 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); }