⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 blkmtd-24.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		pagenr++;		pages--;		unlock_page(page);		if(!PageDirty(page))			page_cache_release(page);	} readerr:	kfree(pagelst);	kfree(pagenrs);	DEBUG(2, "blkmtd: end read: retlen = %zd, err = %d\n", *retlen, err);	return err;}/* write data to the underlying device */static int blkmtd_write(struct mtd_info *mtd, loff_t to, size_t len,			size_t *retlen, const u_char *buf){	struct blkmtd_dev *dev = mtd->priv;	int err;	*retlen = 0;	if(!len)		return 0;	DEBUG(2, "blkmtd: write: dev = `%s' to = %lld len = %zd buf = %p\n",	      bdevname(dev->binding->bd_dev), to, len, buf);	/* handle readonly and out of range numbers */	if(!dev->wr_buf) {		err("error: trying to write to a readonly device %s", mtd->name);		return -EROFS;	}	if(to >= mtd->size) {		return -ENOSPC;	}	if(to + len > mtd->size) {		len = (mtd->size - to);	}	err = write_pages(dev, buf, to, len, retlen);	if(err < 0)		*retlen = 0;	else		err = 0;	DEBUG(2, "blkmtd: write: end, err = %d\n", err);	return err;}/* sync the device - wait until the write queue is empty */static void blkmtd_sync(struct mtd_info *mtd){	struct blkmtd_dev *dev = mtd->priv;	struct kiobuf *iobuf = dev->wr_buf;	DEBUG(2, "blkmtd: sync: called\n");	if(iobuf == NULL)		return;	DEBUG(3, "blkmtd: kiovec: length = %d nr_pages = %d\n",	      iobuf->length, iobuf->nr_pages);	down(&dev->wrbuf_mutex);	if(iobuf->nr_pages)		commit_pages(dev);	up(&dev->wrbuf_mutex);}#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 len;	struct list_head *temp1, *temp2;	MOD_INC_USE_COUNT;	/* Count the size of the page lists */	len = sprintf(page, "dev\twr_idx\tmax_idx\tnrpages\tclean\tdirty\tlocked\tlru\n");	list_for_each_safe(temp1, temp2, &blkmtd_device_list) {		struct blkmtd_dev *dev = list_entry(temp1,  struct blkmtd_dev,						    list);		struct list_head *temp;		struct page *pagei;		int clean = 0, dirty = 0, locked = 0, lru = 0;		/* Count the size of the page lists */		list_for_each(temp, &dev->binding->bd_inode->i_mapping->clean_pages) {			pagei = list_entry(temp, struct page, list);			clean++;			if(PageLocked(pagei))				locked++;			if(PageDirty(pagei))				dirty++;			if(PageLRU(pagei))				lru++;		}		list_for_each(temp, &dev->binding->bd_inode->i_mapping->dirty_pages) {			pagei = list_entry(temp, struct page, list);			if(PageLocked(pagei))				locked++;			if(PageDirty(pagei))				dirty++;			if(PageLRU(pagei))				lru++;		}		list_for_each(temp, &dev->binding->bd_inode->i_mapping->locked_pages) {			pagei = list_entry(temp, struct page, list);			if(PageLocked(pagei))				locked++;			if(PageDirty(pagei))				dirty++;			if(PageLRU(pagei))				lru++;		}		len += sprintf(page+len, "mtd%d:\t%ld\t%d\t%ld\t%d\t%d\t%d\t%d\n",			       dev->mtd_info.index,			       (dev->wr_buf && dev->wr_buf->nr_pages) ?			       dev->wr_buf->blocks[dev->wr_buf->nr_pages-1] : 0,			       (dev->wr_buf) ? dev->wr_buf->nr_pages : 0,			       dev->binding->bd_inode->i_mapping->nrpages,			       clean, dirty, locked, lru);	}	if(len <= count)		*eof = 1;	MOD_DEC_USE_COUNT;	return len;}#endifstatic void free_device(struct blkmtd_dev *dev){	DEBUG(2, "blkmtd: free_device() dev = %p\n", dev);	if(dev) {		del_mtd_device(&dev->mtd_info);		info("mtd%d: [%s] removed", dev->mtd_info.index,		     dev->mtd_info.name + strlen("blkmtd: "));		if(dev->mtd_info.eraseregions)			kfree(dev->mtd_info.eraseregions);		if(dev->mtd_info.name)			kfree(dev->mtd_info.name);		if(dev->rd_buf) {			dev->rd_buf->locked = 0;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)			if(dev->rd_buf->blocks)				kfree(dev->rd_buf->blocks);#endif			free_kiovec(1, &dev->rd_buf);		}		if(dev->wr_buf) {			dev->wr_buf->locked = 0;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)						if(dev->wr_buf->blocks)				kfree(dev->rw_buf->blocks);#endif			free_kiovec(1, &dev->wr_buf);		}		if(dev->binding) {			kdev_t kdev = to_kdev_t(dev->binding->bd_dev);			invalidate_inode_pages(dev->binding->bd_inode);			set_blocksize(kdev, 1 << 10);			blkdev_put(dev->binding, BDEV_RAW);		}		kfree(dev);	}}/* For a given size and initial erase size, calculate the number * and size of each erase region. Goes round the loop twice, * once to find out how many regions, then allocates space, * then round the loop again to fill it in. */static struct mtd_erase_region_info *calc_erase_regions(	size_t erase_size, size_t total_size, int *regions){	struct mtd_erase_region_info *info = NULL;	DEBUG(2, "calc_erase_regions, es = %zd size = %zd regions = %d\n",	      erase_size, total_size, *regions);	/* Make any user specified erasesize be a power of 2	   and at least PAGE_SIZE */	if(erase_size) {		int es = erase_size;		erase_size = 1;		while(es != 1) {			es >>= 1;			erase_size <<= 1;		}		if(erase_size < PAGE_SIZE)			erase_size = PAGE_SIZE;	} else {		erase_size = CONFIG_MTD_BLKDEV_ERASESIZE;	}	*regions = 0;	do {		int tot_size = total_size;		int er_size = erase_size;		int count = 0, offset = 0, regcnt = 0;		while(tot_size) {			count = tot_size / er_size;			if(count) {				tot_size = tot_size % er_size;				if(info) {					DEBUG(2, "adding to erase info off=%d er=%d cnt=%d\n",					      offset, er_size, count);					(info+regcnt)->offset = offset;					(info+regcnt)->erasesize = er_size;					(info+regcnt)->numblocks = count;					(*regions)++;				}				regcnt++;				offset += (count * er_size);			}			while(er_size > tot_size)				er_size >>= 1;		}		if(info == NULL) {			info = kmalloc(regcnt * sizeof(struct mtd_erase_region_info), GFP_KERNEL);			if(!info)				break;		}	} while(!(*regions));	DEBUG(2, "calc_erase_regions done, es = %zd size = %zd regions = %d\n",	      erase_size, total_size, *regions);	return info;}extern kdev_t name_to_kdev_t(char *line) __init;static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size){	int maj, min;	kdev_t kdev;	int mode;	struct blkmtd_dev *dev;#ifdef MODULE	struct file *file = NULL;	struct inode *inode;#endif	if(!devname)		return NULL;	/* Get a handle on the device */	mode = (readonly) ? O_RDONLY : O_RDWR;#ifdef MODULE	file = filp_open(devname, mode, 0);	if(IS_ERR(file)) {		err("error: cant open device %s", devname);		DEBUG(2, "blkmtd: filp_open returned %ld\n", PTR_ERR(file));		return NULL;	}	/* 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)) {		err("%s not a block device", devname);		filp_close(file, NULL);		return NULL;	}	kdev = inode->i_rdev;	filp_close(file, NULL);#else	kdev = name_to_kdev_t(devname);#endif	/* MODULE */	if(!kdev) {		err("bad block device: `%s'", devname);		return NULL;	}	maj = MAJOR(kdev);	min = MINOR(kdev);	DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n",	      maj, min);	if(maj == MTD_BLOCK_MAJOR) {		err("attempting to use an MTD device as a block device");		return NULL;	}	DEBUG(1, "blkmtd: devname = %s\n", bdevname(kdev));	dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL);	if(dev == NULL)		return NULL;	memset(dev, 0, sizeof(struct blkmtd_dev));	if(alloc_kiovec(1, &dev->rd_buf)) {		err("cant allocate read iobuf");		goto devinit_err;	}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)	dev->rd_buf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);	if(dev->rd_buf->blocks == NULL) {		crit("cant allocate rd_buf blocks");		goto devinit_err;	}#endif		if(!readonly) {		if(alloc_kiovec(1, &dev->wr_buf)) {			err("cant allocate kiobuf - readonly enabled");#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)		} else {			dev->wr_buf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);			if(dev->wr_buf->blocks == NULL) {				crit("cant allocate wr_buf blocks - readonly enabled");				free_kiovec(1, &iobuf);			}#endif		}		if(dev->wr_buf)			init_MUTEX(&dev->wrbuf_mutex);	}	/* get the block device */	dev->binding = bdget(kdev_t_to_nr(MKDEV(maj, min)));	if(blkdev_get(dev->binding, mode, 0, BDEV_RAW))		goto devinit_err;	if(set_blocksize(kdev, PAGE_SIZE)) {		err("cant set block size to PAGE_SIZE on %s", bdevname(kdev));		goto devinit_err;	}	dev->mtd_info.size = dev->binding->bd_inode->i_size & PAGE_MASK;	/* Setup the MTD structure */	/* make the name contain the block device in */	dev->mtd_info.name = kmalloc(sizeof("blkmtd: ") + strlen(devname), GFP_KERNEL);	if(dev->mtd_info.name == NULL)		goto devinit_err;	sprintf(dev->mtd_info.name, "blkmtd: %s", devname);	dev->mtd_info.eraseregions = calc_erase_regions(erase_size, dev->mtd_info.size,							&dev->mtd_info.numeraseregions);	if(dev->mtd_info.eraseregions == NULL)		goto devinit_err;	dev->mtd_info.erasesize = dev->mtd_info.eraseregions->erasesize;	DEBUG(1, "blkmtd: init: found %d erase regions\n",	      dev->mtd_info.numeraseregions);	if(readonly) {		dev->mtd_info.type = MTD_ROM;		dev->mtd_info.flags = MTD_CAP_ROM;	} else {		dev->mtd_info.type = MTD_RAM;		dev->mtd_info.flags = MTD_CAP_RAM;	}	dev->mtd_info.erase = blkmtd_erase;	dev->mtd_info.read = blkmtd_read;	dev->mtd_info.write = blkmtd_write;	dev->mtd_info.sync = blkmtd_sync;	dev->mtd_info.point = 0;	dev->mtd_info.unpoint = 0;	dev->mtd_info.priv = dev;	dev->mtd_info.owner = THIS_MODULE;	list_add(&dev->list, &blkmtd_device_list);	if (add_mtd_device(&dev->mtd_info)) {		/* Device didnt get added, so free the entry */		list_del(&dev->list);		free_device(dev);		return NULL;	} else {		info("mtd%d: [%s] erase_size = %dKiB %s",		     dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "),		     dev->mtd_info.erasesize >> 10,		     (dev->wr_buf) ? "" : "(read-only)");	}		return dev; devinit_err:	free_device(dev);	return NULL;}/* Cleanup and exit - sync the device and kill of the kernel thread */static void __devexit cleanup_blkmtd(void){	struct list_head *temp1, *temp2;#ifdef BLKMTD_PROC_DEBUG	if(blkmtd_proc) {		remove_proc_entry("blkmtd_debug", NULL);	}#endif	/* Remove the MTD devices */	list_for_each_safe(temp1, temp2, &blkmtd_device_list) {		struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,						    list);		blkmtd_sync(&dev->mtd_info);		free_device(dev);	}}#ifndef MODULE/* Handle kernel boot params */static int __init param_blkmtd_device(char *str){	int i;	for(i = 0; i < MAX_DEVICES; i++) {		device[i] = str;		DEBUG(2, "blkmtd: device setup: %d = %s\n", i, device[i]);		strsep(&str, ",");	}	return 1;}static int __init param_blkmtd_erasesz(char *str){	int i;	for(i = 0; i < MAX_DEVICES; i++) {		char *val = strsep(&str, ",");		if(val)			erasesz[i] = simple_strtoul(val, NULL, 0);		DEBUG(2, "blkmtd: erasesz setup: %d = %d\n", i, erasesz[i]);	}	return 1;}static int __init param_blkmtd_ro(char *str){	int i;	for(i = 0; i < MAX_DEVICES; i++) {		char *val = strsep(&str, ",");		if(val)			ro[i] = simple_strtoul(val, NULL, 0);		DEBUG(2, "blkmtd: ro setup: %d = %d\n", i, ro[i]);	}	return 1;}static int __init param_blkmtd_sync(char *str){	if(str[0] == '1')		sync = 1;	return 1;}__setup("blkmtd_device=", param_blkmtd_device);__setup("blkmtd_erasesz=", param_blkmtd_erasesz);__setup("blkmtd_ro=", param_blkmtd_ro);__setup("blkmtd_sync=", param_blkmtd_sync);#endif/* Startup */static int __init init_blkmtd(void){	int i;	/* Check args - device[0] is the bare minimum*/	if(!device[0]) {		err("error: missing `device' name\n");		return -EINVAL;	}	for(i = 0; i < MAX_DEVICES; i++)		add_device(device[i], ro[i], erasesz[i] << 10);	if(list_empty(&blkmtd_device_list))		goto init_err;	info("version " VERSION);#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) {		err("Cant create /proc/blkmtd_debug");	} else {		blkmtd_proc->owner = THIS_MODULE;	}#endif	if(!list_empty(&blkmtd_device_list))		/* Everything is ok if we got here */		return 0; init_err:	return -EINVAL;}module_init(init_blkmtd);module_exit(cleanup_blkmtd);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -