aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2014-02-06 10:47:47 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2014-02-06 10:47:47 -0500
commit774016b2d455017935b3e318b6cc4e055e9dd47f (patch)
tree5f2881c744990f7581f8aea9985079d532475812 /fs/gfs2
parentb2c8b3ea871e478ac144f617d015d3aa55fc3aa8 (diff)
GFS2: journal data writepages update
GFS2 has carried what is more or less a copy of the write_cache_pages() for some time. It seems that this copy has slipped behind the core code over time. This patch brings it back uptodate, and in addition adds the tracepoint which would otherwise be missing. We could go further, and eliminate some or all of the code duplication here. The issue is that if we do that, then the function we need to split out from the existing write_cache_pages(), which will look a lot like gfs2_jdata_write_pagevec(), would land up putting quite a lot of extra variables on the stack. I know that has been a problem in the past in the writeback code path, which is why I've hesitated to do it here. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r--fs/gfs2/aops.c132
1 files changed, 96 insertions, 36 deletions
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index 49436fa7cd4f..ce62dcac90b6 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -21,6 +21,7 @@
21#include <linux/gfs2_ondisk.h> 21#include <linux/gfs2_ondisk.h>
22#include <linux/backing-dev.h> 22#include <linux/backing-dev.h>
23#include <linux/aio.h> 23#include <linux/aio.h>
24#include <trace/events/writeback.h>
24 25
25#include "gfs2.h" 26#include "gfs2.h"
26#include "incore.h" 27#include "incore.h"
@@ -230,13 +231,11 @@ static int gfs2_writepages(struct address_space *mapping,
230static int gfs2_write_jdata_pagevec(struct address_space *mapping, 231static int gfs2_write_jdata_pagevec(struct address_space *mapping,
231 struct writeback_control *wbc, 232 struct writeback_control *wbc,
232 struct pagevec *pvec, 233 struct pagevec *pvec,
233 int nr_pages, pgoff_t end) 234 int nr_pages, pgoff_t end,
235 pgoff_t *done_index)
234{ 236{
235 struct inode *inode = mapping->host; 237 struct inode *inode = mapping->host;
236 struct gfs2_sbd *sdp = GFS2_SB(inode); 238 struct gfs2_sbd *sdp = GFS2_SB(inode);
237 loff_t i_size = i_size_read(inode);
238 pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
239 unsigned offset = i_size & (PAGE_CACHE_SIZE-1);
240 unsigned nrblocks = nr_pages * (PAGE_CACHE_SIZE/inode->i_sb->s_blocksize); 239 unsigned nrblocks = nr_pages * (PAGE_CACHE_SIZE/inode->i_sb->s_blocksize);
241 int i; 240 int i;
242 int ret; 241 int ret;
@@ -248,40 +247,83 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping,
248 for(i = 0; i < nr_pages; i++) { 247 for(i = 0; i < nr_pages; i++) {
249 struct page *page = pvec->pages[i]; 248 struct page *page = pvec->pages[i];
250 249
250 /*
251 * At this point, the page may be truncated or
252 * invalidated (changing page->mapping to NULL), or
253 * even swizzled back from swapper_space to tmpfs file
254 * mapping. However, page->index will not change
255 * because we have a reference on the page.
256 */
257 if (page->index > end) {
258 /*
259 * can't be range_cyclic (1st pass) because
260 * end == -1 in that case.
261 */
262 ret = 1;
263 break;
264 }
265
266 *done_index = page->index;
267
251 lock_page(page); 268 lock_page(page);
252 269
253 if (unlikely(page->mapping != mapping)) { 270 if (unlikely(page->mapping != mapping)) {
271continue_unlock:
254 unlock_page(page); 272 unlock_page(page);
255 continue; 273 continue;
256 } 274 }
257 275
258 if (!wbc->range_cyclic && page->index > end) { 276 if (!PageDirty(page)) {
259 ret = 1; 277 /* someone wrote it for us */
260 unlock_page(page); 278 goto continue_unlock;
261 continue;
262 } 279 }
263 280
264 if (wbc->sync_mode != WB_SYNC_NONE) 281 if (PageWriteback(page)) {
265 wait_on_page_writeback(page); 282 if (wbc->sync_mode != WB_SYNC_NONE)
266 283 wait_on_page_writeback(page);
267 if (PageWriteback(page) || 284 else
268 !clear_page_dirty_for_io(page)) { 285 goto continue_unlock;
269 unlock_page(page);
270 continue;
271 } 286 }
272 287
273 /* Is the page fully outside i_size? (truncate in progress) */ 288 BUG_ON(PageWriteback(page));
274 if (page->index > end_index || (page->index == end_index && !offset)) { 289 if (!clear_page_dirty_for_io(page))
275 page->mapping->a_ops->invalidatepage(page, 0, 290 goto continue_unlock;
276 PAGE_CACHE_SIZE); 291
277 unlock_page(page); 292 trace_wbc_writepage(wbc, mapping->backing_dev_info);
278 continue;
279 }
280 293
281 ret = __gfs2_jdata_writepage(page, wbc); 294 ret = __gfs2_jdata_writepage(page, wbc);
295 if (unlikely(ret)) {
296 if (ret == AOP_WRITEPAGE_ACTIVATE) {
297 unlock_page(page);
298 ret = 0;
299 } else {
300
301 /*
302 * done_index is set past this page,
303 * so media errors will not choke
304 * background writeout for the entire
305 * file. This has consequences for
306 * range_cyclic semantics (ie. it may
307 * not be suitable for data integrity
308 * writeout).
309 */
310 *done_index = page->index + 1;
311 ret = 1;
312 break;
313 }
314 }
282 315
283 if (ret || (--(wbc->nr_to_write) <= 0)) 316 /*
317 * We stop writing back only if we are not doing
318 * integrity sync. In case of integrity sync we have to
319 * keep going until we have written all the pages
320 * we tagged for writeback prior to entering this loop.
321 */
322 if (--wbc->nr_to_write <= 0 && wbc->sync_mode == WB_SYNC_NONE) {
284 ret = 1; 323 ret = 1;
324 break;
325 }
326
285 } 327 }
286 gfs2_trans_end(sdp); 328 gfs2_trans_end(sdp);
287 return ret; 329 return ret;
@@ -306,51 +348,69 @@ static int gfs2_write_cache_jdata(struct address_space *mapping,
306 int done = 0; 348 int done = 0;
307 struct pagevec pvec; 349 struct pagevec pvec;
308 int nr_pages; 350 int nr_pages;
351 pgoff_t uninitialized_var(writeback_index);
309 pgoff_t index; 352 pgoff_t index;
310 pgoff_t end; 353 pgoff_t end;
311 int scanned = 0; 354 pgoff_t done_index;
355 int cycled;
312 int range_whole = 0; 356 int range_whole = 0;
357 int tag;
313 358
314 pagevec_init(&pvec, 0); 359 pagevec_init(&pvec, 0);
315 if (wbc->range_cyclic) { 360 if (wbc->range_cyclic) {
316 index = mapping->writeback_index; /* Start from prev offset */ 361 writeback_index = mapping->writeback_index; /* prev offset */
362 index = writeback_index;
363 if (index == 0)
364 cycled = 1;
365 else
366 cycled = 0;
317 end = -1; 367 end = -1;
318 } else { 368 } else {
319 index = wbc->range_start >> PAGE_CACHE_SHIFT; 369 index = wbc->range_start >> PAGE_CACHE_SHIFT;
320 end = wbc->range_end >> PAGE_CACHE_SHIFT; 370 end = wbc->range_end >> PAGE_CACHE_SHIFT;
321 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) 371 if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
322 range_whole = 1; 372 range_whole = 1;
323 scanned = 1; 373 cycled = 1; /* ignore range_cyclic tests */
324 } 374 }
375 if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)
376 tag = PAGECACHE_TAG_TOWRITE;
377 else
378 tag = PAGECACHE_TAG_DIRTY;
325 379
326retry: 380retry:
327 while (!done && (index <= end) && 381 if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)
328 (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, 382 tag_pages_for_writeback(mapping, index, end);
329 PAGECACHE_TAG_DIRTY, 383 done_index = index;
330 min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) { 384 while (!done && (index <= end)) {
331 scanned = 1; 385 nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag,
332 ret = gfs2_write_jdata_pagevec(mapping, wbc, &pvec, nr_pages, end); 386 min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
387 if (nr_pages == 0)
388 break;
389
390 ret = gfs2_write_jdata_pagevec(mapping, wbc, &pvec, nr_pages, end, &done_index);
333 if (ret) 391 if (ret)
334 done = 1; 392 done = 1;
335 if (ret > 0) 393 if (ret > 0)
336 ret = 0; 394 ret = 0;
337
338 pagevec_release(&pvec); 395 pagevec_release(&pvec);
339 cond_resched(); 396 cond_resched();
340 } 397 }
341 398
342 if (!scanned && !done) { 399 if (!cycled && !done) {
343 /* 400 /*
401 * range_cyclic:
344 * We hit the last page and there is more work to be done: wrap 402 * We hit the last page and there is more work to be done: wrap
345 * back to the start of the file 403 * back to the start of the file
346 */ 404 */
347 scanned = 1; 405 cycled = 1;
348 index = 0; 406 index = 0;
407 end = writeback_index - 1;
349 goto retry; 408 goto retry;
350 } 409 }
351 410
352 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) 411 if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
353 mapping->writeback_index = index; 412 mapping->writeback_index = done_index;
413
354 return ret; 414 return ret;
355} 415}
356 416