lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20151215202216.GA11742@chopperman.am.freescale.net>
Date:	Tue, 15 Dec 2015 14:22:17 -0600
From:	Han Xu <han.xu@...escale.com>
To:	Michal Suchanek <hramrach@...il.com>
CC:	Heiner Kallweit <hkallweit1@...il.com>,
	David Woodhouse <dwmw2@...radead.org>,
	Brian Norris <computersforpeace@...il.com>,
	Mark Brown <broonie@...nel.org>,
	Boris Brezillon <boris.brezillon@...e-electrons.com>,
	Javier Martinez Canillas <javier@....samsung.com>,
	Rafal Milecki <zajec5@...il.com>,
	Jagan Teki <jteki@...nedev.com>,
	"Andrew F. Davis" <afd@...com>,
	Mika Westerberg <mika.westerberg@...ux.intel.com>,
	Gabor Juhos <juhosg@...nwrt.org>,
	Bean Huo <beanhuo@...ron.com>,
	Furquan Shaikh <furquan@...gle.com>,
	<linux-mtd@...ts.infradead.org>, <linux-kernel@...r.kernel.org>,
	<linux-spi@...r.kernel.org>
Subject: Re: [PATCH v6 06/10] mtd: spi-nor: simplify write loop

On Wed, Dec 02, 2015 at 10:38:20AM +0000, Michal Suchanek wrote:
> The spi-nor write loop assumes that what is passed to the hardware
> driver write() is what gets written.
> 
> When write() writes less than page size at once data is dropped on the
> floor. Check the amount of data writen and exit if it does not match
> requested amount.
> 
> Signed-off-by: Michal Suchanek <hramrach@...il.com>
> 
> ---
> 
>  - add warning when writing incomplete pages
>  - refuse to continue writing when full page was not written
> ---
>  drivers/mtd/spi-nor/spi-nor.c | 58 +++++++++++++++++++------------------------
>  1 file changed, 25 insertions(+), 33 deletions(-)
> 
> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
> index 3d02803..115c123 100644
> --- a/drivers/mtd/spi-nor/spi-nor.c
> +++ b/drivers/mtd/spi-nor/spi-nor.c
> @@ -1005,8 +1005,8 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
>  	size_t *retlen, const u_char *buf)
>  {
>  	struct spi_nor *nor = mtd_to_spi_nor(mtd);
> -	u32 page_offset, page_size, i;
> -	int ret;
> +	size_t page_offset, page_remain, i;
> +	ssize_t ret;
>  
>  	dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
>  
> @@ -1014,45 +1014,37 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
>  	if (ret)
>  		return ret;
>  
> -	write_enable(nor);
> -
> -	page_offset = to & (nor->page_size - 1);
> +	for (i = 0; i < len; ) {
> +		ssize_t written;
>  
> -	/* do all the bytes fit onto one page? */
> -	if (page_offset + len <= nor->page_size) {
> -		ret = nor->write(nor, to, len, buf);
> -		if (ret < 0)
> -			goto write_err;
> -		*retlen += ret;
> -	} else {
> +		page_offset = to & (nor->page_size - 1);
> +		WARN_ONCE(page_offset,
> +			  "Writing at offset %zu into a NOR page. Writing partial pages may decrease reliability and increase wear of NOR flash.",
> +			  page_offset);
>  		/* the size of data remaining on the first page */
> -		page_size = nor->page_size - page_offset;
> -		ret = nor->write(nor, to, page_size, buf);
> +		page_remain = min_t(size_t,
> +				    nor->page_size - page_offset, len - i);
> +
> +		write_enable(nor);
> +		ret = nor->write(nor, to + i, page_remain, buf + i);

Previous implementation was trying to write nor->page_size byte data in
each loop, except the first and last loop, if possible. But this change
may write only (nor->page_size - page_offset) in each loop, for the
worst case, if page_offset equals nor->page_size -1, it writes byte by
byte.

>  		if (ret < 0)
>  			goto write_err;
> -		*retlen += ret;
> -
> -		/* write everything in nor->page_size chunks */
> -		for (i = ret; i < len; ) {
> -			page_size = len - i;
> -			if (page_size > nor->page_size)
> -				page_size = nor->page_size;
> -
> -			ret = spi_nor_wait_till_ready(nor);
> -			if (ret)
> -				goto write_err;
> +		written = ret;
>  
> -			write_enable(nor);
> -
> -			ret = nor->write(nor, to + i, page_size, buf + i);
> -			if (ret < 0)
> -				goto write_err;
> -			*retlen += ret;
> -			i += ret;
> +		ret = spi_nor_wait_till_ready(nor);
> +		if (ret)
> +			goto write_err;
> +		*retlen += written;
> +		i += written;
> +		if (written != page_remain) {
> +			dev_err(nor->dev,
> +				"While writing %zu bytes written %zd bytes\n",
> +				page_remain, written);
> +			ret = -EIO;
> +			goto write_err;
>  		}
>  	}
>  
> -	ret = spi_nor_wait_till_ready(nor);
>  write_err:
>  	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
>  	return ret;
> -- 
> 2.6.2
> 

-- 
Best Regards,

Han "Allen" Xu

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ