📄 blkmtd.c
字号:
current->state = TASK_RUNNING; remove_wait_queue(&mtbd_sync_wq, &wait); DEBUG(3, "blkmtd: sync: waking up after write task\n"); goto stuff_inq; } spin_unlock(&mbd_writeq_lock); DEBUG(2, "blkmtd: sync: finished\n");}#ifdef BLKMTD_PROC_DEBUG/* procfs stuff */static int blkmtd_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data){ int clean = 0, dirty = 0, locked = 0; struct list_head *temp; int i, len, pages = 0, cnt; MOD_INC_USE_COUNT; spin_lock(&mbd_writeq_lock); cnt = write_queue_cnt; i = write_queue_tail; while(cnt) { if(!write_queue[i].iserase) pages += write_queue[i].pagecnt; i++; i %= write_queue_sz; cnt--; } /* Count the size of the page lists */ list_for_each(temp, &mtd_rawdevice->as.clean_pages) { clean++; } list_for_each(temp, &mtd_rawdevice->as.dirty_pages) { dirty++; } list_for_each(temp, &mtd_rawdevice->as.locked_pages) { locked++; } len = sprintf(page, "Write queue head: %d\nWrite queue tail: %d\n" "Write queue count: %d\nPages in queue: %d (%dK)\n" "Clean Pages: %d\nDirty Pages: %d\nLocked Pages: %d\n" "nrpages: %ld\n", write_queue_head, write_queue_tail, write_queue_cnt, pages, pages << (PAGE_SHIFT-10), clean, dirty, locked, mtd_rawdevice->as.nrpages); if(len <= count) *eof = 1; spin_unlock(&mbd_writeq_lock); MOD_DEC_USE_COUNT; return len;}#endif/* Cleanup and exit - sync the device and kill of the kernel thread */static void __exit cleanup_blkmtd(void){#ifdef BLKMTD_PROC_DEBUG if(blkmtd_proc) { remove_proc_entry("blkmtd_debug", NULL); }#endif if (mtd_rawdevice) { /* sync the device */ if (!mtd_rawdevice->readonly) { blkmtd_sync(&mtd_rawdevice->mtd_info); write_task_finish = 1; wake_up_interruptible(&thr_wq); down(&thread_sem); } del_mtd_device(&mtd_rawdevice->mtd_info); if(mtd_rawdevice->binding != NULL) blkdev_put(mtd_rawdevice->binding, BDEV_RAW); if(mtd_rawdevice->mtd_info.eraseregions) kfree(mtd_rawdevice->mtd_info.eraseregions); if(mtd_rawdevice->mtd_info.name) kfree(mtd_rawdevice->mtd_info.name); kfree(mtd_rawdevice); } if(write_queue) kfree(write_queue); if(erase_page) { UnlockPage(erase_page); __free_pages(erase_page, 0); } printk("blkmtd: unloaded for %s\n", device);}extern struct module __this_module;#ifndef MODULE/* Handle kernel boot params */static int __init param_blkmtd_device(char *str){ device = str; return 1;}static int __init param_blkmtd_erasesz(char *str){ erasesz = simple_strtol(str, NULL, 0); return 1;}static int __init param_blkmtd_ro(char *str){ ro = simple_strtol(str, NULL, 0); return 1;}static int __init param_blkmtd_bs(char *str){ bs = simple_strtol(str, NULL, 0); return 1;}static int __init param_blkmtd_count(char *str){ count = simple_strtol(str, NULL, 0); return 1;}__setup("blkmtd_device=", param_blkmtd_device);__setup("blkmtd_erasesz=", param_blkmtd_erasesz);__setup("blkmtd_ro=", param_blkmtd_ro);__setup("blkmtd_bs=", param_blkmtd_bs);__setup("blkmtd_count=", param_blkmtd_count);#endif/* for a given size and initial erase size, calculate the number and size of each erase region */static int __init calc_erase_regions(struct mtd_erase_region_info *info, size_t erase_size, size_t total_size){ int count = 0; int offset = 0; int regions = 0; while(total_size) { count = total_size / erase_size; if(count) { total_size = total_size % erase_size; if(info) { info->offset = offset; info->erasesize = erase_size; info->numblocks = count; info++; } offset += (count * erase_size); regions++; } while(erase_size > total_size) erase_size >>= 1; } return regions;}extern kdev_t name_to_kdev_t(char *line) __init;/* Startup */static int __init init_blkmtd(void){#ifdef MODULE struct file *file = NULL; struct inode *inode;#endif int maj, min; int i, blocksize, blocksize_bits; loff_t size = 0; int readonly = 0; int erase_size = CONFIG_MTD_BLKDEV_ERASESIZE; kdev_t rdev; int err; int mode; int regions; /* Check args */ if(device == 0) { printk("blkmtd: error, missing `device' name\n"); return -EINVAL; } if(ro) readonly = 1; if(erasesz) erase_size = erasesz; if(wqs) { if(wqs < 16) wqs = 16; if(wqs > 4*WRITE_QUEUE_SZ) wqs = 4*WRITE_QUEUE_SZ; write_queue_sz = wqs; } DEBUG(1, "blkmtd: device = `%s' erase size = %dK readonly = %s queue size = %d\n", device, erase_size, readonly ? "yes" : "no", write_queue_sz); /* Get a handle on the device */ mode = (readonly) ? O_RDONLY : O_RDWR;#ifdef MODULE file = filp_open(device, mode, 0); if(IS_ERR(file)) { printk("blkmtd: error, cant open device %s\n", device); DEBUG(2, "blkmtd: filp_open returned %ld\n", PTR_ERR(file)); return 1; } /* determine is this is a block device and if so get its major and minor numbers */ inode = file->f_dentry->d_inode; if(!S_ISBLK(inode->i_mode)) { printk("blkmtd: %s not a block device\n", device); filp_close(file, NULL); return 1; } rdev = inode->i_rdev; filp_close(file, NULL);#else rdev = name_to_kdev_t(device);#endif maj = MAJOR(rdev); min = MINOR(rdev); DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n", maj, min); if(!rdev) { printk("blkmtd: bad block device: `%s'\n", device); return 1; } if(maj == MTD_BLOCK_MAJOR) { printk("blkmtd: attempting to use an MTD device as a block device\n"); return 1; } DEBUG(1, "blkmtd: devname = %s\n", bdevname(rdev)); blocksize = BLOCK_SIZE; if(bs) { blocksize = bs; } else { if (blksize_size[maj] && blksize_size[maj][min]) { DEBUG(2, "blkmtd: blksize_size = %d\n", blksize_size[maj][min]); blocksize = blksize_size[maj][min]; } } i = blocksize; blocksize_bits = 0; while(i != 1) { blocksize_bits++; i >>= 1; } if(count) { size = count; } else { if (blk_size[maj]) { size = ((loff_t) blk_size[maj][min] << BLOCK_SIZE_BITS) >> blocksize_bits; } } size *= blocksize; DEBUG(1, "blkmtd: size = %ld\n", (long int)size); if(size == 0) { printk("blkmtd: cant determine size\n"); return 1; } mtd_rawdevice = (mtd_raw_dev_data_t *)kmalloc(sizeof(mtd_raw_dev_data_t), GFP_KERNEL); if(mtd_rawdevice == NULL) { err = -ENOMEM; goto init_err; } memset(mtd_rawdevice, 0, sizeof(mtd_raw_dev_data_t)); /* get the block device */ mtd_rawdevice->binding = bdget(kdev_t_to_nr(MKDEV(maj, min))); err = blkdev_get(mtd_rawdevice->binding, mode, 0, BDEV_RAW); if (err) { goto init_err; } mtd_rawdevice->totalsize = size; mtd_rawdevice->sector_size = blocksize; mtd_rawdevice->sector_bits = blocksize_bits; mtd_rawdevice->readonly = readonly; /* See if device ends on page boundary */ if(size % PAGE_SIZE) { mtd_rawdevice->partial_last_page = size >> PAGE_SHIFT; mtd_rawdevice->last_page_sectors = (size & (PAGE_SIZE-1)) >> blocksize_bits; } DEBUG(2, "sector_size = %d, sector_bits = %d, partial_last_page = %d last_page_sectors = %d\n", mtd_rawdevice->sector_size, mtd_rawdevice->sector_bits, mtd_rawdevice->partial_last_page, mtd_rawdevice->last_page_sectors); /* Setup the MTD structure */ /* make the name contain the block device in */ mtd_rawdevice->mtd_info.name = kmalloc(9 + strlen(device), GFP_KERNEL); if(mtd_rawdevice->mtd_info.name == NULL) goto init_err; sprintf(mtd_rawdevice->mtd_info.name, "blkmtd: %s", device); if(readonly) { mtd_rawdevice->mtd_info.type = MTD_ROM; mtd_rawdevice->mtd_info.flags = MTD_CAP_ROM; mtd_rawdevice->mtd_info.erasesize = erase_size << 10; } else { mtd_rawdevice->mtd_info.type = MTD_RAM; mtd_rawdevice->mtd_info.flags = MTD_CAP_RAM; mtd_rawdevice->mtd_info.erasesize = erase_size << 10; } mtd_rawdevice->mtd_info.size = size; mtd_rawdevice->mtd_info.erase = blkmtd_erase; mtd_rawdevice->mtd_info.read = blkmtd_read; mtd_rawdevice->mtd_info.write = blkmtd_write; mtd_rawdevice->mtd_info.sync = blkmtd_sync; mtd_rawdevice->mtd_info.point = 0; mtd_rawdevice->mtd_info.unpoint = 0; mtd_rawdevice->mtd_info.priv = mtd_rawdevice; regions = calc_erase_regions(NULL, erase_size << 10, size); DEBUG(1, "blkmtd: init: found %d erase regions\n", regions); mtd_rawdevice->mtd_info.eraseregions = kmalloc(regions * sizeof(struct mtd_erase_region_info), GFP_KERNEL); if(mtd_rawdevice->mtd_info.eraseregions == NULL) { err = -ENOMEM; goto init_err; } mtd_rawdevice->mtd_info.numeraseregions = regions; calc_erase_regions(mtd_rawdevice->mtd_info.eraseregions, erase_size << 10, size); /* setup the page cache info */ mtd_rawdevice->as.nrpages = 0; INIT_LIST_HEAD(&mtd_rawdevice->as.clean_pages); INIT_LIST_HEAD(&mtd_rawdevice->as.dirty_pages); INIT_LIST_HEAD(&mtd_rawdevice->as.locked_pages); mtd_rawdevice->as.host = NULL; spin_lock_init(&(mtd_rawdevice->as.i_shared_lock)); mtd_rawdevice->as.a_ops = &blkmtd_aops; mtd_rawdevice->as.i_mmap = NULL; mtd_rawdevice->as.i_mmap_shared = NULL; mtd_rawdevice->as.gfp_mask = GFP_KERNEL;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) mtd_rawdevice->mtd_info.module = THIS_MODULE; #endif if (add_mtd_device(&mtd_rawdevice->mtd_info)) { err = -EIO; goto init_err; } if(!mtd_rawdevice->readonly) { /* Allocate the write queue */ write_queue = kmalloc(write_queue_sz * sizeof(mtdblkdev_write_queue_t), GFP_KERNEL); if(!write_queue) { err = -ENOMEM; goto init_err; } /* Set up the erase page */ erase_page = alloc_pages(GFP_KERNEL, 0); if(erase_page == NULL) { err = -ENOMEM; goto init_err; } memset(page_address(erase_page), 0xff, PAGE_SIZE); lock_page(erase_page); init_waitqueue_head(&thr_wq); init_waitqueue_head(&mtbd_sync_wq); DEBUG(3, "blkmtd: init: kernel task @ %p\n", write_queue_task); DEBUG(2, "blkmtd: init: starting kernel task\n"); kernel_thread(write_queue_task, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); DEBUG(2, "blkmtd: init: started\n"); printk("blkmtd loaded: version = %s using %s erase_size = %dK %s\n", VERSION, device, erase_size, (readonly) ? "(read-only)" : ""); }#ifdef BLKMTD_PROC_DEBUG /* create proc entry */ DEBUG(2, "Creating /proc/blkmtd_debug\n"); blkmtd_proc = create_proc_read_entry("blkmtd_debug", 0444, NULL, blkmtd_proc_read, NULL); if(blkmtd_proc == NULL) { printk("Cant create /proc/blkmtd_debug\n"); } else { blkmtd_proc->owner = THIS_MODULE; }#endif /* Everything is ok if we got here */ return 0; init_err: if(mtd_rawdevice) { if(mtd_rawdevice->mtd_info.eraseregions) kfree(mtd_rawdevice->mtd_info.eraseregions); if(mtd_rawdevice->mtd_info.name) kfree(mtd_rawdevice->mtd_info.name); if(mtd_rawdevice->binding) blkdev_put(mtd_rawdevice->binding, BDEV_RAW); kfree(mtd_rawdevice); } if(write_queue) { kfree(write_queue); write_queue = NULL; } if(erase_page) __free_pages(erase_page, 0); return err;}module_init(init_blkmtd);module_exit(cleanup_blkmtd);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -