/* erase a specified part of the device */ staticint _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
{ struct address_space *mapping = dev->bdev_file->f_mapping; struct page *page;
pgoff_t index = to >> PAGE_SHIFT; // page index int pages = len >> PAGE_SHIFT;
u_long *p;
u_long *max;
while (pages) {
page = page_read(mapping, index); if (IS_ERR(page)) return PTR_ERR(page);
max = page_address(page) + PAGE_SIZE; for (p=page_address(page); p<max; p++) if (*p != -1UL) {
lock_page(page);
memset(page_address(page), 0xff, PAGE_SIZE);
set_page_dirty(page);
unlock_page(page);
balance_dirty_pages_ratelimited(mapping); break;
}
put_page(page);
pages--;
index++;
} return0;
} staticint block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
{ struct block2mtd_dev *dev = mtd->priv;
size_t from = instr->addr;
size_t len = instr->len; int err;
/* write data to the underlying device */ staticint _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
loff_t to, size_t len, size_t *retlen)
{ struct page *page; struct address_space *mapping = dev->bdev_file->f_mapping;
pgoff_t index = to >> PAGE_SHIFT; // page index int offset = to & ~PAGE_MASK; // page offset int cpylen;
while (len) { if ((offset+len) > PAGE_SIZE)
cpylen = PAGE_SIZE - offset; // multiple pages else
cpylen = len; // this page
len = len - cpylen;
page = page_read(mapping, index); if (IS_ERR(page)) return PTR_ERR(page);
dev = kzalloc(sizeof(struct block2mtd_dev), GFP_KERNEL); if (!dev) return NULL;
/* Get a handle on the device */
bdev_file = bdev_file_open_by_path(devname, mode, dev, NULL); if (IS_ERR(bdev_file))
bdev_file = mdtblock_early_get_bdev(devname, mode, timeout,
dev); if (IS_ERR(bdev_file)) {
pr_err("error: cannot open device %s\n", devname); goto err_free_block2mtd;
}
dev->bdev_file = bdev_file;
bdev = file_bdev(bdev_file);
if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
pr_err("attempting to use an MTD device as a block device\n"); goto err_free_block2mtd;
}
size = bdev_nr_bytes(bdev); if ((long)size % erase_size) {
pr_err("erasesize must be a divisor of device size\n"); goto err_free_block2mtd;
}
mutex_init(&dev->write_mutex);
/* Setup the MTD structure */ /* make the name contain the block device in */ if (!label)
name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname); else
name = kstrdup(label, GFP_KERNEL); if (!name) goto err_destroy_mutex;
/* This function works similar to reguler strtoul. In addition, it *allowssomesuffixesforamorehuman-readablenumberformat: *ki,Ki,kiB,KiB-multiplyresultwith1024 *Mi,MiB-multiplyresultwith1024^2 *Gi,GiB-multiplyresultwith1024^3
*/ staticint ustrtoul(constchar *cp, char **endp, unsignedint base)
{ unsignedlong result = simple_strtoul(cp, endp, base); switch (**endp) { case'G' :
result *= 1024;
fallthrough; case'M':
result *= 1024;
fallthrough; case'K': case'k':
result *= 1024; /* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */ if ((*endp)[1] == 'i') { if ((*endp)[2] == 'B')
(*endp) += 3; else
(*endp) += 2;
}
} return result;
}
#ifndef MODULE staticint block2mtd_init_called = 0; /* 80 for device, 12 for erase size */ staticchar block2mtd_paramline[80 + 12]; #endif
staticint block2mtd_setup2(constchar *val)
{ /* 80 for device, 12 for erase size, 80 for name, 8 for timeout */ char buf[80 + 12 + 80 + 8]; char *str = buf; char *token[BLOCK2MTD_PARAM_MAX_COUNT]; char *name; char *label = NULL;
size_t erase_size = PAGE_SIZE; unsignedlong timeout = MTD_DEFAULT_TIMEOUT; int i, ret;
if (strnlen(val, sizeof(buf)) >= sizeof(buf)) {
pr_err("parameter too long\n"); return0;
}
strcpy(str, val);
kill_final_newline(str);
for (i = 0; i < BLOCK2MTD_PARAM_MAX_COUNT; i++)
token[i] = strsep(&str, ",");
if (str) {
pr_err("too many arguments\n"); return0;
}
if (!token[0]) {
pr_err("no argument\n"); return0;
}
name = token[0]; if (strlen(name) + 1 > 80) {
pr_err("device name too long\n"); return0;
}
/* Optional argument when custom label is used */ if (token[1] && strlen(token[1])) {
ret = parse_num(&erase_size, token[1]); if (ret) {
pr_err("illegal erase size\n"); return0;
}
}
if (token[2]) {
label = token[2];
pr_info("Using custom MTD label '%s' for dev %s\n", label, name);
}
add_device(name, erase_size, label, timeout);
return0;
}
staticint block2mtd_setup(constchar *val, conststruct kernel_param *kp)
{ #ifdef MODULE return block2mtd_setup2(val); #else /* If more parameters are later passed in via /sys/module/block2mtd/parameters/block2mtd andblock2mtd_init()hasalreadybeencalled,
we can parse the argument now. */
if (block2mtd_init_called) return block2mtd_setup2(val);
/* During early boot stage, we only save the parameters here.Wemustparsethemlater:iftheparampassed fromkernelbootcommandline,block2mtd_setup()is calledsoearlythatitisnotpossibletoresolve thedevice(evenkmalloc()fails).Deterthatworkto
block2mtd_setup2(). */
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.