关于linux squash文件系统挂载的时候如何检查坏块

linux挂载squash的时候默认不检查坏块,当遇到坏块的时候会挂载失败,确认linux内核版本 LINUX_VERSION_CODE >= KERNEL_VERSION(4,5,0)
以下为novatek 98560使用的内核上的修改,按添加说明添加即可

1、/drivers/mtd/mtdpart.c文件中添加函数

#define CONFIG_SKIP_SQUASHFS_BAD_BLOCK
#ifdef CONFIG_SKIP_SQUASHFS_BAD_BLOCK
#include <linux/mtd/nand.h>
#include <linux/mtd/rawnand.h>
#define MAX_PARTITION_MAPPING   4

struct part_map{
    struct mtd_info *part_mtd;  /* Mapping partition mtd */
    unsigned *map_table;        /* Mapping from logic block to phys block */
    unsigned nBlock;            /* Logic block number */
};

static struct part_map *part_mapping[MAX_PARTITION_MAPPING];
static int part_mapping_count = -1;

static loff_t ajust_offset(struct mtd_info *mtd, loff_t from)
{
    struct mtd_part *part = mtd_to_part(mtd);
    struct nand_chip *this = part->parent->priv;
    unsigned logic_b, phys_b;
    unsigned index;

    if(part_mapping_count <= 0)
        return from;

    for( index = 0; index < MAX_PARTITION_MAPPING; index++ )
    {
        if(!part_mapping[index] || part_mapping[index]->part_mtd != mtd)
            continue;
		
        /* remap from logic block to physical block */
        logic_b = from >> this->bbt_erase_shift;
        if ( logic_b < part_mapping[index]->nBlock )
        {
            phys_b = part_mapping[index]->map_table[logic_b];
            from = phys_b << this->bbt_erase_shift | (from&(mtd->erasesize-1));
            break;
        }
    }

    return from;
}

static int part_create_partition_mapping ( struct mtd_info *part_mtd )
{
    struct mtd_part *part = mtd_to_part(part_mtd);
    struct nand_chip *this = part->parent->priv;
    struct part_map *map_part;
    int index;
    unsigned offset;
    int logical_b, phys_b;

    if (!part_mtd || !this || part_mtd->type == MTD_NORFLASH)
    {
        printk("null mtd or it is no nand chip!");
        return -1;
    }

    if ( part_mapping_count < 0 )
    {
        /* Init the part mapping table when this function called first time */
        memset(part_mapping, 0, sizeof(struct part_map *)*MAX_PARTITION_MAPPING);
        part_mapping_count = 0;
    }

    for ( index = 0; index < MAX_PARTITION_MAPPING; index++ )
    {
        if ( part_mapping[index] == NULL )
            break;
    }

    if ( index >= MAX_PARTITION_MAPPING )
    {
        printk("partition mapping is full!");
        return -1;
    }

    map_part = kmalloc(sizeof(struct part_map), GFP_KERNEL);
    if ( !map_part )
    {
        printk ("memory allocation error while creating partitions mapping for %s/n",
                part_mtd->name);
        return -1;
    }

    map_part->map_table = kmalloc(sizeof(unsigned)*(part_mtd->size>>this->bbt_erase_shift),
                                  GFP_KERNEL);
    if ( !map_part->map_table )
    {
        printk ("memory allocation error while creating partitions mapping for %s/n", part_mtd->name);
        kfree(map_part);
        return -1;
    }
    memset(map_part->map_table, 0xFF, sizeof(unsigned)*(part_mtd->size>>this->bbt_erase_shift));

    /* Create partition mapping table */
    logical_b = 0;
    for ( offset=0; offset<part_mtd->size; offset+=part_mtd->erasesize )
    {
        if ( part_mtd->_block_isbad &&
             part_mtd->_block_isbad(part_mtd, offset) )
			continue;

        phys_b = offset >> this->bbt_erase_shift;
        map_part->map_table[logical_b] = phys_b;
        //printk("part[%s]: logic[%u]=phys[%u]\n",part_mtd->name, logical_b, phys_b);
        logical_b++;
    }
    map_part->nBlock = logical_b;
    map_part->part_mtd = part_mtd;

    part_mapping[index] = map_part;
    part_mapping_count++;

    return 0;
}

static void part_del_partition_mapping( struct mtd_info *part_mtd )
{
    int index;
    struct part_map *map_part;

    if (part_mapping_count <= 0)
        return;

    for (index = 0; index < MAX_PARTITION_MAPPING; index++ )
    {
        map_part = part_mapping[index];

        if(!map_part || map_part->part_mtd != part_mtd)
            continue;

        kfree(map_part->map_table);
        kfree(map_part);
        part_mapping[index] = NULL;
        part_mapping_count--;
    }
}

static int part_is_squashfs( struct mtd_info *part_mtd )
{
	struct mtd_part *part = mtd_to_part(part_mtd);
    struct nand_chip *this = part->parent->priv;

    u_char buf[16];
    size_t retlen;
    unsigned offset;
    unsigned check_size = part_mtd->erasesize*2;

    if (!part_mtd || !this || part_mtd->type == MTD_NORFLASH)
    {
        //printk("null mtd or it is no nand chip!");
        return 0;
    }

    for (offset=0; offset<check_size; offset+=part_mtd->erasesize)
    {
        if (part_mtd->_block_isbad &&
             part_mtd->_block_isbad(part_mtd, offset))
        {
            // 防止要检查的开始几个块是坏块
            check_size += part_mtd->erasesize;
            continue;
        }
             

        if(part_mtd->_read)
        {
            part_mtd->_read(part_mtd, offset, 16, &retlen, buf);
            if(!memcmp(buf, "hsqs", 4))
            {
                // printk("%s:%d partition is squashfs,%s\n", __func__, __LINE__,buf);
                return 1;
            }
        }
    }

    return 0;
}
#endif

下面的函数添加相关代码

static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
		size_t *retlen, u_char *buf)
{
	struct mtd_part *part = mtd_to_part(mtd);
	struct mtd_ecc_stats stats;
	int res;
//添加下面3行
	#ifdef CONFIG_SKIP_SQUASHFS_BAD_BLOCK
	from = ajust_offset(mtd, from);
	#endif

	stats = part->parent->ecc_stats;
	res = part->parent->_read(part->parent, from + part->offset, len,
				  retlen, buf);
	if (unlikely(mtd_is_eccerr(res)))
		mtd->ecc_stats.failed +=
			part->parent->ecc_stats.failed - stats.failed;
	else
		mtd->ecc_stats.corrected +=
			part->parent->ecc_stats.corrected - stats.corrected;
	return res;
}

static int part_read_oob(struct mtd_info *mtd, loff_t from,
		struct mtd_oob_ops *ops)
{
	struct mtd_part *part = mtd_to_part(mtd);
	struct mtd_ecc_stats stats;
	int res;
//添加下面3行
	#ifdef CONFIG_SKIP_SQUASHFS_BAD_BLOCK
	from = ajust_offset(mtd, from);
	#endif

	stats = part->parent->ecc_stats;
	res = part->parent->_read_oob(part->parent, from + part->offset, ops);
	if (unlikely(mtd_is_eccerr(res)))
		mtd->ecc_stats.failed +=
			part->parent->ecc_stats.failed - stats.failed;
	else
		mtd->ecc_stats.corrected +=
			part->parent->ecc_stats.corrected - stats.corrected;
	return res;
}

int mtd_add_partition(struct mtd_info *parent, const char *name,
		      long long offset, long long length)
{
	struct mtd_partition part;
	struct mtd_part *new;
	int ret = 0;

	/* the direct offset is expected */
	if (offset == MTDPART_OFS_APPEND ||
	    offset == MTDPART_OFS_NXTBLK)
		return -EINVAL;

	if (length == MTDPART_SIZ_FULL)
		length = parent->size - offset;

	if (length <= 0)
		return -EINVAL;

	memset(&part, 0, sizeof(part));
	part.name = name;
	part.size = length;
	part.offset = offset;

	new = allocate_partition(parent, &part, -1, offset);
	if (IS_ERR(new))
		return PTR_ERR(new);

	mutex_lock(&mtd_partitions_mutex);
	list_add(&new->list, &mtd_partitions);
	mutex_unlock(&mtd_partitions_mutex);

	ret = add_mtd_device(&new->mtd);
	if (ret)
		goto err_remove_part;

	mtd_add_partition_attrs(new);
//添加下面4行
    #ifdef CONFIG_SKIP_SQUASHFS_BAD_BLOCK
        if(part_is_squashfs(&new->mtd))
            part_create_partition_mapping(&new->mtd);
    #endif
	return 0;

err_remove_part:
	mutex_lock(&mtd_partitions_mutex);
	list_del(&new->list);
	mutex_unlock(&mtd_partitions_mutex);

	free_partition(new);

	return ret;
}


int del_mtd_partitions(struct mtd_info *mtd)
{
	struct mtd_part *slave, *next;
	int ret, err = 0;

	mutex_lock(&mtd_partitions_mutex);
	list_for_each_entry_safe(slave, next, &mtd_partitions, list)
		if (slave->parent == mtd) {
		//添加下面3行
			#ifdef CONFIG_SKIP_SQUASHFS_BAD_BLOCK
			part_del_partition_mapping(&slave->mtd);
			#endif

			ret = __mtd_del_partition(slave);
			if (ret < 0)
				err = ret;
		}
	mutex_unlock(&mtd_partitions_mutex);

	return err;
}

int mtd_del_partition(struct mtd_info *mtd, int partno)
{
	struct mtd_part *slave, *next;
	int ret = -EINVAL;

	mutex_lock(&mtd_partitions_mutex);
	list_for_each_entry_safe(slave, next, &mtd_partitions, list)
		if ((slave->parent == mtd) &&
		    (slave->mtd.index == partno)) {
		    //添加下面3行
            #ifdef CONFIG_SKIP_SQUASHFS_BAD_BLOCK
            part_del_partition_mapping(&slave->mtd);
            #endif

			ret = __mtd_del_partition(slave);
			break;
		}
	mutex_unlock(&mtd_partitions_mutex);

	return ret;
}

int add_mtd_partitions(struct mtd_info *master,
		       const struct mtd_partition *parts,
		       int nbparts)
{
	struct mtd_part *slave;
	uint64_t cur_offset = 0;
	int i, ret;

	printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);

	for (i = 0; i < nbparts; i++) {
		slave = allocate_partition(master, parts + i, i, cur_offset);
		if (IS_ERR(slave)) {
			ret = PTR_ERR(slave);
			goto err_del_partitions;
		}

		mutex_lock(&mtd_partitions_mutex);
		list_add(&slave->list, &mtd_partitions);
		mutex_unlock(&mtd_partitions_mutex);

		ret = add_mtd_device(&slave->mtd);
		if (ret) {
			mutex_lock(&mtd_partitions_mutex);
			list_del(&slave->list);
			mutex_unlock(&mtd_partitions_mutex);

			free_partition(slave);
			goto err_del_partitions;
		}

		mtd_add_partition_attrs(slave);
		/* Look for subpartitions */
		parse_mtd_partitions(&slave->mtd, parts[i].types, NULL);
//添加下面4行
		#ifdef CONFIG_SKIP_SQUASHFS_BAD_BLOCK
            if(part_is_squashfs(&slave->mtd))
                part_create_partition_mapping(&slave->mtd);
        #endif

		cur_offset = slave->offset + slave->mtd.size;
	}

	return 0;

err_del_partitions:
	del_mtd_partitions(master);

	return ret;
}

2、/drivers/mtd/nand/raw/nand_base.c修改如下

确认下面函数是否非定义,未定义就要定义下面函数

static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
		     size_t *retlen, uint8_t *buf)
{
	struct mtd_oob_ops ops;
	int ret;

	nand_get_device(mtd, FL_READING);
	memset(&ops, 0, sizeof(ops));
	ops.len = len;
	ops.datbuf = buf;
	ops.mode = MTD_OPS_PLACE_OOB;
	ret = nand_do_read_ops(mtd, from, &ops);
	*retlen = ops.retlen;
	nand_release_device(mtd);
	return ret;
}
//找到static int nand_scan_tail(struct mtd_info *mtd)函数
	/* Fill in remaining MTD driver data */
	mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH;
	mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
						MTD_CAP_NANDFLASH;
	mtd->_erase = nand_erase;
	mtd->_point = NULL;
	mtd->_unpoint = NULL;
	mtd->_panic_write = panic_nand_write;
	mtd->_read = nand_read;//如果没有赋值就赋值
	mtd->_read_oob = nand_read_oob;
	mtd->_write_oob = nand_write_oob;
	mtd->_sync = nand_sync;
	mtd->_lock = NULL;
	mtd->_unlock = NULL;
	mtd->_suspend = nand_suspend;
	mtd->_resume = nand_resume;
	mtd->_reboot = nand_shutdown;
	mtd->_block_isreserved = nand_block_isreserved;
	mtd->_block_isbad = nand_block_isbad;//如果没有赋值就赋值,
	mtd->_block_markbad = nand_block_markbad;
	mtd->_max_bad_blocks = nand_max_bad_blocks;
	mtd->writebufsize = mtd->writesize;
//mtd->_block_isbad和mtd->_read = nand_read这两个函数在检查的时候要用,确认这里赋值

3、修改/drivers/mtd/spiflash/spinand.c文件如下

static int spinand_probe(struct platform_device *pdev)
{
	struct drv_nand_dev_info *info;
	struct mtd_part_parser_data ppdata;
	struct platform_nand_data *pplatdata;
	struct nand_chip *this;
	struct mtd_info *mtd;
	struct resource *res;
	int ret = 0;
	u8 chip_id;
	//添加下面2行
    static const char *part_probes[] = { "cmdlinepart", NULL, };
    int err = 0;

	info = devm_kzalloc(&pdev->dev, sizeof(struct drv_nand_dev_info), GFP_KERNEL);
	if (!info)
		return -ENOMEM;

	info->pdev = pdev;

	info->flash_info = kmalloc(sizeof(struct nvt_nand_flash), GFP_KERNEL);
	if (!info->flash_info) {
		dev_err(&pdev->dev, "failed to allocate nvt_nand_flash\n");
		return -ENOMEM;
	}

	pplatdata = NULL;
	if (pdev->dev.platform_data != NULL)
	{
		pplatdata = pdev->dev.platform_data;
	}

	platform_set_drvdata(pdev, info);
	this = &info->nand_chip;
	mtd = nand_to_mtd(this);
	//添加下面2行
    /* Initialize structures */
    mtd->priv = this;


	/* Get mtd device resource of base address */
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

	if (!res) {
		dev_err(&pdev->dev, "failed to get resource\n");
		goto fail_free_mtd;
	}

	info->mmio_base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(info->mmio_base)) {
		PTR_ERR(info->mmio_base);
		goto fail_free_mtd;
	}

	info->irq = platform_get_irq(pdev, 0);
	if (info->irq < 0) {
		dev_err(&pdev->dev, "no IRQ resource defined\n");
		ret = -ENXIO;
		goto fail_free_mtd;
	}

	ret = drv_nand_init_buff(info);
	if (ret) {
		dev_err(&pdev->dev, "failed to allocate buffer\n");
		goto fail_free_buf;
	}

	ret = request_irq(info->irq, spinand_irq, IRQF_SHARED, pdev->name, info);
	if (ret < 0) {
		dev_err(&pdev->dev, "failed to request IRQ\n");
		goto fail_free_buf;
	}

	of_property_read_u32(pdev->dev.of_node, "clock-frequency",
				&info->flash_freq);

	mutex_init(&info->lock);

	init_completion(&info->cmd_complete);

	mutex_lock(&info->lock);
	drv_nand_reset(info, pdev);
	nand_phy_config(info);
	nand_dll_reset(info);
	mutex_unlock(&info->lock);
	/*Delay 1ms for spinand characteristic*/
	mdelay(1);

	ret = drv_nand_identify(info);

	if (ret) {
		dev_err(&pdev->dev, "failed to identify flash\n");
		ret = -ENODEV;
		goto fail_free_irq;
	}

	spinand_init_mtd(info);

	nand_set_flash_node(&info->nand_chip, pdev->dev.of_node);

#ifdef CONFIG_OF
	of_property_read_string_index(pdev->dev.of_node, "nvt-devname", 0, &mtd->name);
#else
	mtd->name = dev_name(&pdev->dev);
#endif
	mtd->owner = THIS_MODULE;
	mtd->oobsize = 64;

	chip_id = info->flash_info->chip_id & 0xFF;
	if (info->use_ecc == NANDCTRL_SPIFLASH_USE_INTERNAL_RS_ECC) {
			info->nand_chip.ecc.strength = 4;
			mtd->bitflip_threshold = 2;
	} else {
		if (chip_id == MFG_ID_WINBOND) {
			if (info->flash_info->chip_id == WINBOND_W25N02KV) {
				info->nand_chip.ecc.strength = 8;
				mtd->bitflip_threshold = 6;
			} else
				mtd->bitflip_threshold = 1;
		} else if (chip_id == MFG_ID_MXIC) {
			info->nand_chip.ecc.strength = 4;
			mtd->bitflip_threshold = 3;
        } else if (chip_id == MFG_ID_MICRON) {
            if (((info->flash_info->chip_id) & 0xFFFF) == MICRON_MT29F1G01AA) {
                mtd->bitflip_threshold = 1;
            } else {
                info->nand_chip.ecc.strength = 8;
        		mtd->bitflip_threshold = 6;
            }
		} else if (chip_id == MFG_ID_TOSHIBA) {
			if (info->flash_info->page_size == 4096) {
				info->nand_chip.ecc.strength = 8;
				mtd->bitflip_threshold = 6;
			} else {
				info->nand_chip.ecc.strength = 8;
				mtd->bitflip_threshold = 3;
			}
		} else if (chip_id == MFG_ID_XTX) {
			info->nand_chip.ecc.strength = 8;
			mtd->bitflip_threshold = 6;
		} else {
            mtd->bitflip_threshold = DIV_ROUND_UP(info->nand_chip.ecc.strength * 3, 4);
		}
	}

#ifndef CONFIG_FLASH_ONLY_DUAL
	if ((info->flash_info->chip_id & 0xFFFF) != TOSHIBA_TC58CVG && (info->flash_info->chip_id & 0xFFFF) != TOSHIBA_TC58CVG3)
		info->flash_info->spi_nand_status.quad_program = TRUE;
#endif

	ret = nand_scan_with_ids(mtd, 1, spinand_flash_ids);
	if (ret) {
		dev_err(&pdev->dev, "Identify nand fail\n");
		goto fail_free_irq;
	}

	dev_info(&pdev->dev, "%d-bit mode @ %d Hz\n",
		 info->flash_info->spi_nand_status.quad_program ? 4 : 1,
		 info->flash_freq);
//添加下面4行
	err = parse_mtd_partitions(mtd, part_probes, 0);
	if (err) {
		dev_err(&pdev->dev, "parse_mtd_partitions failed\n");
	}

	ret = nvt_nand_proc_init();
	if (ret) {
		dev_err(&pdev->dev, "create nand static proc failed\n");
	}

	//ppdata.of_node = pdev->dev.of_node;
	mtd->dev.of_node = pdev->dev.of_node;;
	if (pplatdata == NULL)
		return mtd_device_register(mtd, NULL, 0);
	else
		return mtd_device_parse_register(mtd, NULL, &ppdata,
				pplatdata->chip.partitions,
				pplatdata->chip.nr_partitions);

fail_free_irq:
	free_irq(info->irq, info);

fail_free_buf:
	kfree(info->data_buff);

fail_free_mtd:
	kfree(mtd);
	return ret;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值