aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeng Tao <bergwolf@gmail.com>2012-08-23 12:27:52 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-10-01 18:38:29 -0400
commitf742dc4a32587bff50b13dde9d8894b96851951a (patch)
treebeedd26b6424ab5bc8dd63fcc04644c5023a4803
parentfe6e1e8d9fad86873eb74a26e80a8f91f9e870b5 (diff)
pnfsblock: fix non-aligned DIO read
For DIO read, if it is not sector aligned, we should reject it and resend via MDS. Otherwise there might be data corruption. Also teach bl_read_pagelist to handle partial page reads for DIO. Cc: stable <stable@vger.kernel.org> [since v3.4] Signed-off-by: Peng Tao <tao.peng@emc.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/blocklayout/blocklayout.c64
1 files changed, 56 insertions, 8 deletions
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c
index a9fe644a12d1..61e04fb7c4b8 100644
--- a/fs/nfs/blocklayout/blocklayout.c
+++ b/fs/nfs/blocklayout/blocklayout.c
@@ -252,8 +252,11 @@ bl_read_pagelist(struct nfs_read_data *rdata)
252 sector_t isect, extent_length = 0; 252 sector_t isect, extent_length = 0;
253 struct parallel_io *par; 253 struct parallel_io *par;
254 loff_t f_offset = rdata->args.offset; 254 loff_t f_offset = rdata->args.offset;
255 size_t bytes_left = rdata->args.count;
256 unsigned int pg_offset, pg_len;
255 struct page **pages = rdata->args.pages; 257 struct page **pages = rdata->args.pages;
256 int pg_index = rdata->args.pgbase >> PAGE_CACHE_SHIFT; 258 int pg_index = rdata->args.pgbase >> PAGE_CACHE_SHIFT;
259 const bool is_dio = (header->dreq != NULL);
257 260
258 dprintk("%s enter nr_pages %u offset %lld count %u\n", __func__, 261 dprintk("%s enter nr_pages %u offset %lld count %u\n", __func__,
259 rdata->pages.npages, f_offset, (unsigned int)rdata->args.count); 262 rdata->pages.npages, f_offset, (unsigned int)rdata->args.count);
@@ -287,36 +290,53 @@ bl_read_pagelist(struct nfs_read_data *rdata)
287 extent_length = min(extent_length, cow_length); 290 extent_length = min(extent_length, cow_length);
288 } 291 }
289 } 292 }
293
294 if (is_dio) {
295 pg_offset = f_offset & ~PAGE_CACHE_MASK;
296 if (pg_offset + bytes_left > PAGE_CACHE_SIZE)
297 pg_len = PAGE_CACHE_SIZE - pg_offset;
298 else
299 pg_len = bytes_left;
300
301 f_offset += pg_len;
302 bytes_left -= pg_len;
303 isect += (pg_offset >> SECTOR_SHIFT);
304 } else {
305 pg_offset = 0;
306 pg_len = PAGE_CACHE_SIZE;
307 }
308
290 hole = is_hole(be, isect); 309 hole = is_hole(be, isect);
291 if (hole && !cow_read) { 310 if (hole && !cow_read) {
292 bio = bl_submit_bio(READ, bio); 311 bio = bl_submit_bio(READ, bio);
293 /* Fill hole w/ zeroes w/o accessing device */ 312 /* Fill hole w/ zeroes w/o accessing device */
294 dprintk("%s Zeroing page for hole\n", __func__); 313 dprintk("%s Zeroing page for hole\n", __func__);
295 zero_user_segment(pages[i], 0, PAGE_CACHE_SIZE); 314 zero_user_segment(pages[i], pg_offset, pg_len);
296 print_page(pages[i]); 315 print_page(pages[i]);
297 SetPageUptodate(pages[i]); 316 SetPageUptodate(pages[i]);
298 } else { 317 } else {
299 struct pnfs_block_extent *be_read; 318 struct pnfs_block_extent *be_read;
300 319
301 be_read = (hole && cow_read) ? cow_read : be; 320 be_read = (hole && cow_read) ? cow_read : be;
302 bio = bl_add_page_to_bio(bio, rdata->pages.npages - i, 321 bio = do_add_page_to_bio(bio, rdata->pages.npages - i,
303 READ, 322 READ,
304 isect, pages[i], be_read, 323 isect, pages[i], be_read,
305 bl_end_io_read, par); 324 bl_end_io_read, par,
325 pg_offset, pg_len);
306 if (IS_ERR(bio)) { 326 if (IS_ERR(bio)) {
307 header->pnfs_error = PTR_ERR(bio); 327 header->pnfs_error = PTR_ERR(bio);
308 bio = NULL; 328 bio = NULL;
309 goto out; 329 goto out;
310 } 330 }
311 } 331 }
312 isect += PAGE_CACHE_SECTORS; 332 isect += (pg_len >> SECTOR_SHIFT);
313 extent_length -= PAGE_CACHE_SECTORS; 333 extent_length -= PAGE_CACHE_SECTORS;
314 } 334 }
315 if ((isect << SECTOR_SHIFT) >= header->inode->i_size) { 335 if ((isect << SECTOR_SHIFT) >= header->inode->i_size) {
316 rdata->res.eof = 1; 336 rdata->res.eof = 1;
317 rdata->res.count = header->inode->i_size - f_offset; 337 rdata->res.count = header->inode->i_size - rdata->args.offset;
318 } else { 338 } else {
319 rdata->res.count = (isect << SECTOR_SHIFT) - f_offset; 339 rdata->res.count = (isect << SECTOR_SHIFT) - rdata->args.offset;
320 } 340 }
321out: 341out:
322 bl_put_extent(be); 342 bl_put_extent(be);
@@ -1149,9 +1169,37 @@ bl_clear_layoutdriver(struct nfs_server *server)
1149 return 0; 1169 return 0;
1150} 1170}
1151 1171
1172static bool
1173is_aligned_req(struct nfs_page *req, unsigned int alignment)
1174{
1175 return IS_ALIGNED(req->wb_offset, alignment) &&
1176 IS_ALIGNED(req->wb_bytes, alignment);
1177}
1178
1179static void
1180bl_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
1181{
1182 if (pgio->pg_dreq != NULL &&
1183 !is_aligned_req(req, SECTOR_SIZE))
1184 nfs_pageio_reset_read_mds(pgio);
1185 else
1186 pnfs_generic_pg_init_read(pgio, req);
1187}
1188
1189static bool
1190bl_pg_test_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
1191 struct nfs_page *req)
1192{
1193 if (pgio->pg_dreq != NULL &&
1194 !is_aligned_req(req, SECTOR_SIZE))
1195 return false;
1196
1197 return pnfs_generic_pg_test(pgio, prev, req);
1198}
1199
1152static const struct nfs_pageio_ops bl_pg_read_ops = { 1200static const struct nfs_pageio_ops bl_pg_read_ops = {
1153 .pg_init = pnfs_generic_pg_init_read, 1201 .pg_init = bl_pg_init_read,
1154 .pg_test = pnfs_generic_pg_test, 1202 .pg_test = bl_pg_test_read,
1155 .pg_doio = pnfs_generic_pg_readpages, 1203 .pg_doio = pnfs_generic_pg_readpages,
1156}; 1204};
1157 1205