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

From: Paolo 'Blaisorblade' Giarrusso
Date: Sun Sep 18 2005 - 09:25:33 EST


From: Paolo 'Blaisorblade' Giarrusso <blaisorblade@xxxxxxxx>

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 <blaisorblade@xxxxxxxx>
---

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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/