[PATCH 07/12] HPPFS: fix broken read method

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Paolo 'Blaisorblade' Giarrusso <[email protected]>

When data to be read has been loaded in memory (sadly kmalloc'ed() memory,
not buffer cache, but I hope it doesn't really matter), we alloc memory one
page at a time, and chain the pages. On a read, we properly walk the page
list, but we fail to handle reads which cross a page boundary.

This patch should fix that. But please, cross check this with
drivers/char/mem.c as I did or use a paper sheet to check it
(as I've done) - it's absolutely nontrivial to get right.

Signed-off-by: Paolo 'Blaisorblade' Giarrusso <[email protected]>
---

 fs/hppfs/hppfs_kern.c |   61 +++++++++++++++++++++++++++++++------------------
 1 files changed, 38 insertions(+), 23 deletions(-)

diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
--- a/fs/hppfs/hppfs_kern.c
+++ b/fs/hppfs/hppfs_kern.c
@@ -302,40 +302,55 @@ static ssize_t hppfs_read(struct file *f
 	struct hppfs_private *hppfs = file->private_data;
 	struct hppfs_data *data;
 	loff_t off;
-	int err;
+	int err, written = 0;
 
 	if (hppfs->contents != NULL) {
-		if(*ppos >= hppfs->len) return(0);
-
-		data = hppfs->contents;
 		off = *ppos;
-		while(off >= sizeof(data->contents)){
-			data = list_entry(data->list.next, struct hppfs_data,
-					  list);
-			off -= sizeof(data->contents);
-		}
 
-		if(off + count > hppfs->len)
+		if (off >= hppfs->len)
+			return 0;
+
+		if (off + count > hppfs->len)
 			count = hppfs->len - off;
-		/*XXX: we should walk the list of remaining buffers! */
-		err = copy_to_user(buf, &data->contents[off], count);
-		count -= err;
-		if (!count)
-			return -EFAULT;
-		*ppos += count;
-	} else if(hppfs->host_fd != -1) {
+
+		data = hppfs->contents;
+		while (count) {
+			int chunk;
+			while (off >= sizeof(data->contents)) {
+				data = list_entry(data->list.next,
+						struct hppfs_data, list);
+				off -= sizeof(data->contents);
+			}
+
+			chunk = min_t(size_t, sizeof(data->contents) - off, count);
+			err = copy_to_user(buf, &data->contents[off], chunk);
+			if (err) {
+				*ppos += chunk - err;
+				written += chunk - err;
+				if (written == 0)
+					written = -EFAULT;
+				break;
+			}
+			off += chunk;
+			buf += chunk;
+			count -= chunk;
+			written += chunk;
+		}
+		*ppos += written;
+	} else if (hppfs->host_fd != -1) {
 		err = os_seek_file(hppfs->host_fd, *ppos);
 		if (err < 0){
 			printk("hppfs_read : seek failed, errno = %d\n", err);
 			return(err);
 		}
-		count = hppfs_read_file(hppfs->host_fd, buf, count);
-		if(count > 0)
-			*ppos += count;
-	} else
-		count = read_proc(hppfs->proc_file, buf, count, ppos, 1);
+		written = hppfs_read_file(hppfs->host_fd, buf, count);
+		*ppos += written;
+	} else {
+		/* It handles ppos on its own */
+		written = read_proc(hppfs->proc_file, buf, count, ppos, 1);
+	}
 
-	return(count);
+	return written;
 }
 
 static ssize_t hppfs_write(struct file *file, const char *buf, size_t len,

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

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]
  Powered by Linux