diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index b51decf401816e..b818a8a026ccbd 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -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; @@ -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); @@ -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; }