|
@@ -166,10 +166,23 @@ static int mtd_close(struct inode *inode, struct file *file)
|
|
|
return 0;
|
|
|
} /* mtd_close */
|
|
|
|
|
|
-/* FIXME: This _really_ needs to die. In 2.5, we should lock the
|
|
|
- userspace buffer down and use it directly with readv/writev.
|
|
|
-*/
|
|
|
-#define MAX_KMALLOC_SIZE 0x20000
|
|
|
+/* Back in June 2001, dwmw2 wrote:
|
|
|
+ *
|
|
|
+ * FIXME: This _really_ needs to die. In 2.5, we should lock the
|
|
|
+ * userspace buffer down and use it directly with readv/writev.
|
|
|
+ *
|
|
|
+ * The implementation below, using mtd_kmalloc_up_to, mitigates
|
|
|
+ * allocation failures when the system is under low-memory situations
|
|
|
+ * or if memory is highly fragmented at the cost of reducing the
|
|
|
+ * performance of the requested transfer due to a smaller buffer size.
|
|
|
+ *
|
|
|
+ * A more complex but more memory-efficient implementation based on
|
|
|
+ * get_user_pages and iovecs to cover extents of those pages is a
|
|
|
+ * longer-term goal, as intimated by dwmw2 above. However, for the
|
|
|
+ * write case, this requires yet more complex head and tail transfer
|
|
|
+ * handling when those head and tail offsets and sizes are such that
|
|
|
+ * alignment requirements are not met in the NAND subdriver.
|
|
|
+ */
|
|
|
|
|
|
static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)
|
|
|
{
|
|
@@ -179,6 +192,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
|
|
|
size_t total_retlen=0;
|
|
|
int ret=0;
|
|
|
int len;
|
|
|
+ size_t size = count;
|
|
|
char *kbuf;
|
|
|
|
|
|
DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n");
|
|
@@ -189,23 +203,12 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
|
|
|
if (!count)
|
|
|
return 0;
|
|
|
|
|
|
- /* FIXME: Use kiovec in 2.5 to lock down the user's buffers
|
|
|
- and pass them directly to the MTD functions */
|
|
|
-
|
|
|
- if (count > MAX_KMALLOC_SIZE)
|
|
|
- kbuf=kmalloc(MAX_KMALLOC_SIZE, GFP_KERNEL);
|
|
|
- else
|
|
|
- kbuf=kmalloc(count, GFP_KERNEL);
|
|
|
-
|
|
|
+ kbuf = mtd_kmalloc_up_to(mtd, &size);
|
|
|
if (!kbuf)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
while (count) {
|
|
|
-
|
|
|
- if (count > MAX_KMALLOC_SIZE)
|
|
|
- len = MAX_KMALLOC_SIZE;
|
|
|
- else
|
|
|
- len = count;
|
|
|
+ len = min_t(size_t, count, size);
|
|
|
|
|
|
switch (mfi->mode) {
|
|
|
case MTD_MODE_OTP_FACTORY:
|
|
@@ -268,6 +271,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
|
|
|
{
|
|
|
struct mtd_file_info *mfi = file->private_data;
|
|
|
struct mtd_info *mtd = mfi->mtd;
|
|
|
+ size_t size = count;
|
|
|
char *kbuf;
|
|
|
size_t retlen;
|
|
|
size_t total_retlen=0;
|
|
@@ -285,20 +289,12 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
|
|
|
if (!count)
|
|
|
return 0;
|
|
|
|
|
|
- if (count > MAX_KMALLOC_SIZE)
|
|
|
- kbuf=kmalloc(MAX_KMALLOC_SIZE, GFP_KERNEL);
|
|
|
- else
|
|
|
- kbuf=kmalloc(count, GFP_KERNEL);
|
|
|
-
|
|
|
+ kbuf = mtd_kmalloc_up_to(mtd, &size);
|
|
|
if (!kbuf)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
while (count) {
|
|
|
-
|
|
|
- if (count > MAX_KMALLOC_SIZE)
|
|
|
- len = MAX_KMALLOC_SIZE;
|
|
|
- else
|
|
|
- len = count;
|
|
|
+ len = min_t(size_t, count, size);
|
|
|
|
|
|
if (copy_from_user(kbuf, buf, len)) {
|
|
|
kfree(kbuf);
|