Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a78bc83 authored by Christian Riesch's avatar Christian Riesch Committed by Brian Norris
Browse files

mtd: Fix the behavior of OTP write if there is not enough room for data

If a write to one time programmable memory (OTP) hits the end of this
memory area, no more data can be written. The count variable in
mtdchar_write() in drivers/mtd/mtdchar.c is not decreased anymore.
We are trapped in the loop forever, mtdchar_write() will never return
in this case.

The desired behavior of a write in such a case is described in [1]:
- Try to write as much data as possible, truncate the write to fit into
  the available memory and return the number of bytes that actually
  have been written.
- If no data could be written at all, return -ENOSPC.

This patch fixes the behavior of OTP write if there is not enough space
for all data:

1) mtd_write_user_prot_reg() in drivers/mtd/mtdcore.c is modified to
   return -ENOSPC if no data could be written at all.
2) mtdchar_write() is modified to handle -ENOSPC correctly. Exit if a
   write returned -ENOSPC and yield the correct return value, either
   then number of bytes that could be written, or -ENOSPC, if no data
   could be written at all.

Furthermore the patch harmonizes the behavior of the OTP memory write
in drivers/mtd/devices/mtd_dataflash.c with the other implementations
and the requirements from [1]. Instead of returning -EINVAL if the data
does not fit into the OTP memory, we try to write as much data as
possible/truncate the write.

[1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html



Signed-off-by: default avatarChristian Riesch <christian.riesch@omicron.at>
Signed-off-by: default avatarBrian Norris <computersforpeace@gmail.com>
parent ea6d833a
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -542,14 +542,18 @@ static int dataflash_write_user_otp(struct mtd_info *mtd,
	struct dataflash	*priv = mtd->priv;
	int			status;

	if (len > 64)
		return -EINVAL;

	/* Strictly speaking, we *could* truncate the write ... but
	 * let's not do that for the only write that's ever possible.
	if (from >= 64) {
		/*
		 * Attempting to write beyond the end of OTP memory,
		 * no data can be written.
		 */
		*retlen = 0;
		return 0;
	}

	/* Truncate the write to fit into OTP memory. */
	if ((from + len) > 64)
		return -EINVAL;
		len = 64 - from;

	/* OUT: OP_WRITE_SECURITY, 3 zeroes, 64 data-or-zero bytes
	 * IN:  ignore all
+9 −0
Original line number Diff line number Diff line
@@ -324,6 +324,15 @@ static ssize_t mtdchar_write(struct file *file, const char __user *buf, size_t c
		default:
			ret = mtd_write(mtd, *ppos, len, &retlen, kbuf);
		}

		/*
		 * Return -ENOSPC only if no data could be written at all.
		 * Otherwise just return the number of bytes that actually
		 * have been written.
		 */
		if ((ret == -ENOSPC) && (total_retlen))
			break;

		if (!ret) {
			*ppos += retlen;
			total_retlen += retlen;
+11 −1
Original line number Diff line number Diff line
@@ -932,12 +932,22 @@ EXPORT_SYMBOL_GPL(mtd_read_user_prot_reg);
int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
			    size_t *retlen, u_char *buf)
{
	int ret;

	*retlen = 0;
	if (!mtd->_write_user_prot_reg)
		return -EOPNOTSUPP;
	if (!len)
		return 0;
	return mtd->_write_user_prot_reg(mtd, to, len, retlen, buf);
	ret = mtd->_write_user_prot_reg(mtd, to, len, retlen, buf);
	if (ret)
		return ret;

	/*
	 * If no data could be written at all, we are out of memory and
	 * must return -ENOSPC.
	 */
	return (*retlen) ? 0 : -ENOSPC;
}
EXPORT_SYMBOL_GPL(mtd_write_user_prot_reg);