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

📄 blkmtd.c

📁 老版本的mtd-snap
💻 C
📖 第 1 页 / 共 2 页
字号:
		}		numregions--;		einfo++;	}	if(!numregions) {		/* Not a valid erase block */		err("erase: invalid erase request 0x%lX @ 0x%08zX", len, from);		instr->state = MTD_ERASE_FAILED;		err = -EIO;	}	if(instr->state != MTD_ERASE_FAILED) {		/* do the erase */		DEBUG(3, "Doing erase from = %zd len = %ld\n", from, len);		err = write_pages(dev, NULL, from, len, &retlen);		if(err || retlen != len) {			err("erase failed err = %d", err);			instr->state = MTD_ERASE_FAILED;		} else {			instr->state = MTD_ERASE_DONE;		}	}	DEBUG(3, "blkmtd: erase: checking callback\n");	mtd_erase_callback(instr);	DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err);	return err;}/* read a range of the data via the page cache */static int blkmtd_read(struct mtd_info *mtd, loff_t from, size_t len,		       size_t *retlen, u_char *buf){	struct blkmtd_dev *dev = mtd->priv;	int err = 0;	int offset;	int pagenr, pages;	size_t thislen = 0;	DEBUG(2, "blkmtd: read: dev = `%s' from = %lld len = %zd buf = %p\n",	      mtd->name+9, from, len, buf);	if(from > mtd->size)		return -EINVAL;	if(from + len > mtd->size)		len = mtd->size - from;	pagenr = from >> PAGE_SHIFT;	offset = from - (pagenr << PAGE_SHIFT);	pages = (offset+len+PAGE_SIZE-1) >> PAGE_SHIFT;	DEBUG(3, "blkmtd: read: pagenr = %d offset = %d, pages = %d\n",	      pagenr, offset, pages);	while(pages) {		struct page *page;		int cpylen;		DEBUG(3, "blkmtd: read: looking for page: %d\n", pagenr);		page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev);		if(IS_ERR(page)) {			err = -EIO;			goto readerr;		}		cpylen = (PAGE_SIZE > len) ? len : PAGE_SIZE;		if(offset+cpylen > PAGE_SIZE)			cpylen = PAGE_SIZE-offset;		memcpy(buf + thislen, page_address(page) + offset, cpylen);		offset = 0;		len -= cpylen;		thislen += cpylen;		pagenr++;		pages--;		if(!PageDirty(page))			page_cache_release(page);	} readerr:	if(retlen)		*retlen = thislen;	DEBUG(2, "blkmtd: end read: retlen = %zd, err = %d\n", thislen, 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;	if(!len)		return 0;	DEBUG(2, "blkmtd: write: dev = `%s' to = %lld len = %zd buf = %p\n",	      mtd->name+9, to, len, buf);	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)		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){	/* Currently all writes are synchronous */}static void free_device(struct blkmtd_dev *dev){	DEBUG(2, "blkmtd: free_device() dev = %p\n", dev);	if(dev) {		if(dev->mtd_info.eraseregions)			kfree(dev->mtd_info.eraseregions);		if(dev->mtd_info.name)			kfree(dev->mtd_info.name);		if(dev->blkdev) {			invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping);			close_bdev_excl(dev->blkdev);		}		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 dev_t __init name_to_dev_t(const char *line);static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size){	struct block_device *bdev;	int mode;	struct blkmtd_dev *dev;	if(!devname)		return NULL;	/* Get a handle on the device */#ifdef MODULE	mode = (readonly) ? O_RDONLY : O_RDWR;	bdev = open_bdev_excl(devname, mode, NULL);#else	mode = (readonly) ? FMODE_READ : FMODE_WRITE;	bdev = open_by_devnum(name_to_dev_t(devname), mode);#endif	if(IS_ERR(bdev)) {		err("error: cannot open device %s", devname);		DEBUG(2, "blkmtd: opening bdev returned %ld\n", PTR_ERR(bdev));		return NULL;	}	DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n",	      MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));	if(MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {		err("attempting to use an MTD device as a block device");		blkdev_put(bdev);		return NULL;	}	dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL);	if(dev == NULL) {		blkdev_put(bdev);		return NULL;	}	memset(dev, 0, sizeof(struct blkmtd_dev));	dev->blkdev = bdev;	if(!readonly) {		init_MUTEX(&dev->wrbuf_mutex);	}	dev->mtd_info.size = dev->blkdev->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.write = blkmtd_write;		dev->mtd_info.writev = default_mtd_writev;		dev->mtd_info.sync = blkmtd_sync;	}	dev->mtd_info.read = blkmtd_read;	dev->mtd_info.readv = default_mtd_readv;	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);		goto devinit_err;	} else {		info("mtd%d: [%s] erase_size = %dKiB %s",		     dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "),		     dev->mtd_info.erasesize >> 10,		     readonly ? "(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;	/* 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);		del_mtd_device(&dev->mtd_info);		info("mtd%d: [%s] removed", dev->mtd_info.index,		     dev->mtd_info.name + strlen("blkmtd: "));		list_del(&dev->list);		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;	info("version " VERSION);	/* 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))		return -EINVAL;	return 0;}module_init(init_blkmtd);module_exit(cleanup_blkmtd);

⌨️ 快捷键说明

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