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,



-------------------------------------------------------
SF.Net email is sponsored by:
Tame your development challenges with Apache's Geronimo App Server. Download
it for free - -and be entered to win a 42" plasma tv or your very own
Sony(tm)PSP.  Click here to play: http://sourceforge.net/geronimo.php
_______________________________________________
User-mode-linux-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/user-mode-linux-devel

Reply via email to