Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions fs/fuse/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -805,17 +805,28 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
}

/* Do as much copy to/from userspace buffer as we can */
static int fuse_copy_do(struct fuse_copy_state *cs, void **val, unsigned *size)
static int fuse_copy_do(struct fuse_copy_state *cs, void **val, unsigned *size,
bool use_copy_page)
{
unsigned ncpy = min(*size, cs->len);
if (val) {
void *pgaddr = kmap_local_page(cs->pg);
void *buf = pgaddr + cs->offset;
void *src, *dst;

if (cs->write)
memcpy(buf, *val, ncpy);
else
memcpy(*val, buf, ncpy);
if (cs->write) {
src = *val;
dst = buf;
} else {
src = buf;
dst = *val;
}

if (use_copy_page) {
copy_page(dst, src);
} else {
memcpy(dst, src, ncpy);
}

kunmap_local(pgaddr);
*val += ncpy;
Expand Down Expand Up @@ -1022,10 +1033,13 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
if (page) {
void *mapaddr = kmap_local_page(page);
void *buf = mapaddr + offset;
offset += fuse_copy_do(cs, &buf, &count);
bool use_copy_page = (count == PAGE_SIZE);

offset += fuse_copy_do(cs, &buf, &count, use_copy_page);

kunmap_local(mapaddr);
} else
offset += fuse_copy_do(cs, NULL, &count);
offset += fuse_copy_do(cs, NULL, &count, false);
}
if (page && !cs->write)
flush_dcache_page(page);
Expand Down Expand Up @@ -1064,7 +1078,7 @@ static int fuse_copy_one(struct fuse_copy_state *cs, void *val, unsigned size)
if (err)
return err;
}
fuse_copy_do(cs, &val, &size);
fuse_copy_do(cs, &val, &size, false);
}
return 0;
}
Expand Down