diff options
author | Gerhard Heift <gerhard@heift.name> | 2014-01-30 10:24:01 -0500 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2014-06-12 21:21:56 -0400 |
commit | 550ac1d85ef99f3390a6ea87c70b7683647f6110 (patch) | |
tree | a3753a08098118a0dda00aff8fcf4dc20e3a480a | |
parent | 9b6e817d022fd44fe99db92f00d4b18ac2d8f429 (diff) |
btrfs: new function read_extent_buffer_to_user
This new function reads the content of an extent directly to user memory.
Signed-off-by: Gerhard Heift <Gerhard@Heift.Name>
Signed-off-by: Chris Mason <clm@fb.com>
Acked-by: David Sterba <dsterba@suse.cz>
-rw-r--r-- | fs/btrfs/extent_io.c | 37 | ||||
-rw-r--r-- | fs/btrfs/extent_io.h | 3 |
2 files changed, 40 insertions, 0 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 0b5fa91d9a88..930f23dfaa2b 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -5067,6 +5067,43 @@ void read_extent_buffer(struct extent_buffer *eb, void *dstv, | |||
5067 | } | 5067 | } |
5068 | } | 5068 | } |
5069 | 5069 | ||
5070 | int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dstv, | ||
5071 | unsigned long start, | ||
5072 | unsigned long len) | ||
5073 | { | ||
5074 | size_t cur; | ||
5075 | size_t offset; | ||
5076 | struct page *page; | ||
5077 | char *kaddr; | ||
5078 | char __user *dst = (char __user *)dstv; | ||
5079 | size_t start_offset = eb->start & ((u64)PAGE_CACHE_SIZE - 1); | ||
5080 | unsigned long i = (start_offset + start) >> PAGE_CACHE_SHIFT; | ||
5081 | int ret = 0; | ||
5082 | |||
5083 | WARN_ON(start > eb->len); | ||
5084 | WARN_ON(start + len > eb->start + eb->len); | ||
5085 | |||
5086 | offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1); | ||
5087 | |||
5088 | while (len > 0) { | ||
5089 | page = extent_buffer_page(eb, i); | ||
5090 | |||
5091 | cur = min(len, (PAGE_CACHE_SIZE - offset)); | ||
5092 | kaddr = page_address(page); | ||
5093 | if (copy_to_user(dst, kaddr + offset, cur)) { | ||
5094 | ret = -EFAULT; | ||
5095 | break; | ||
5096 | } | ||
5097 | |||
5098 | dst += cur; | ||
5099 | len -= cur; | ||
5100 | offset = 0; | ||
5101 | i++; | ||
5102 | } | ||
5103 | |||
5104 | return ret; | ||
5105 | } | ||
5106 | |||
5070 | int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start, | 5107 | int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start, |
5071 | unsigned long min_len, char **map, | 5108 | unsigned long min_len, char **map, |
5072 | unsigned long *map_start, | 5109 | unsigned long *map_start, |
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 8b63f2d46518..15ce5f2a2b62 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h | |||
@@ -304,6 +304,9 @@ int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv, | |||
304 | void read_extent_buffer(struct extent_buffer *eb, void *dst, | 304 | void read_extent_buffer(struct extent_buffer *eb, void *dst, |
305 | unsigned long start, | 305 | unsigned long start, |
306 | unsigned long len); | 306 | unsigned long len); |
307 | int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dst, | ||
308 | unsigned long start, | ||
309 | unsigned long len); | ||
307 | void write_extent_buffer(struct extent_buffer *eb, const void *src, | 310 | void write_extent_buffer(struct extent_buffer *eb, const void *src, |
308 | unsigned long start, unsigned long len); | 311 | unsigned long start, unsigned long len); |
309 | void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src, | 312 | void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src, |