aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKinglong Mee <kinglongmee@gmail.com>2015-10-16 05:22:50 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2015-10-21 16:55:47 -0400
commit15ae2c7bdc9a5a46999319b88a465a64d265dc40 (patch)
tree807ec1b53cd955739de97edabfadd30058f71089
parente0a63c0bfcc6f8283377258b5d892f88abd913c1 (diff)
nfs/blocklayout: Fix bad using of page offset in bl_read_pagelist
Blocklayout uses file offset for the read-back page's offset of first writing, it's definitely wrong, it writes data to bad address of page that cause userspace application segment fault. It must be the page base stored in header->args.pgbase. Also, the pg_offset has no influence with isect and extent length. Note: The offset of the non-first page is always zero. Ps: A test program will segment fault at read() as, #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> int main(int argc, char **argv) { char buf[2049]; char *filename = NULL; int fd = -1; if (argc < 2) { printf("Usage: %s filename\n", argv[0]); return 0; } filename = argv[1]; fd = open(filename, O_RDONLY | O_DIRECT); if (fd < 0) { printf("Open %s fail: %m\n", filename); return 1; } lseek(fd, 2048, SEEK_SET); if (read(fd, buf, sizeof(buf) - 1) != (sizeof(buf) - 1)) printf("Read 4096 bityes data from %s fail: %m\n", filename); out: close(fd); return 0; } Signed-off-by: Kinglong Mee <kinglongmee@gmail.com> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
-rw-r--r--fs/nfs/blocklayout/blocklayout.c7
1 files changed, 2 insertions, 5 deletions
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c
index 9cd4eb3a1e22..ddd0138f410c 100644
--- a/fs/nfs/blocklayout/blocklayout.c
+++ b/fs/nfs/blocklayout/blocklayout.c
@@ -229,7 +229,7 @@ bl_read_pagelist(struct nfs_pgio_header *header)
229 struct parallel_io *par; 229 struct parallel_io *par;
230 loff_t f_offset = header->args.offset; 230 loff_t f_offset = header->args.offset;
231 size_t bytes_left = header->args.count; 231 size_t bytes_left = header->args.count;
232 unsigned int pg_offset, pg_len; 232 unsigned int pg_offset = header->args.pgbase, pg_len;
233 struct page **pages = header->args.pages; 233 struct page **pages = header->args.pages;
234 int pg_index = header->args.pgbase >> PAGE_CACHE_SHIFT; 234 int pg_index = header->args.pgbase >> PAGE_CACHE_SHIFT;
235 const bool is_dio = (header->dreq != NULL); 235 const bool is_dio = (header->dreq != NULL);
@@ -262,7 +262,6 @@ bl_read_pagelist(struct nfs_pgio_header *header)
262 extent_length = be.be_length - (isect - be.be_f_offset); 262 extent_length = be.be_length - (isect - be.be_f_offset);
263 } 263 }
264 264
265 pg_offset = f_offset & ~PAGE_CACHE_MASK;
266 if (is_dio) { 265 if (is_dio) {
267 if (pg_offset + bytes_left > PAGE_CACHE_SIZE) 266 if (pg_offset + bytes_left > PAGE_CACHE_SIZE)
268 pg_len = PAGE_CACHE_SIZE - pg_offset; 267 pg_len = PAGE_CACHE_SIZE - pg_offset;
@@ -273,9 +272,6 @@ bl_read_pagelist(struct nfs_pgio_header *header)
273 pg_len = PAGE_CACHE_SIZE; 272 pg_len = PAGE_CACHE_SIZE;
274 } 273 }
275 274
276 isect += (pg_offset >> SECTOR_SHIFT);
277 extent_length -= (pg_offset >> SECTOR_SHIFT);
278
279 if (is_hole(&be)) { 275 if (is_hole(&be)) {
280 bio = bl_submit_bio(READ, bio); 276 bio = bl_submit_bio(READ, bio);
281 /* Fill hole w/ zeroes w/o accessing device */ 277 /* Fill hole w/ zeroes w/o accessing device */
@@ -301,6 +297,7 @@ bl_read_pagelist(struct nfs_pgio_header *header)
301 extent_length -= (pg_len >> SECTOR_SHIFT); 297 extent_length -= (pg_len >> SECTOR_SHIFT);
302 f_offset += pg_len; 298 f_offset += pg_len;
303 bytes_left -= pg_len; 299 bytes_left -= pg_len;
300 pg_offset = 0;
304 } 301 }
305 if ((isect << SECTOR_SHIFT) >= header->inode->i_size) { 302 if ((isect << SECTOR_SHIFT) >= header->inode->i_size) {
306 header->res.eof = 1; 303 header->res.eof = 1;