aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ntfs/aops.c
diff options
context:
space:
mode:
authorAnton Altaparmakov <aia21@cam.ac.uk>2007-10-12 04:37:15 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-12 12:16:30 -0400
commitbfab36e81611e60573b84eb4e4b4c8d8545b2320 (patch)
treeacd151a4c85459dcd2f6575ceb385090ebaaf984 /fs/ntfs/aops.c
parentf26e51f67ae6a75ffc57b96cf5fe096f75e778cb (diff)
NTFS: Fix a mount time deadlock.
Big thanks go to Mathias Kolehmainen for reporting the bug, providing debug output and testing the patches I sent him to get it working. The fix was to stop calling ntfs_attr_set() at mount time as that causes balance_dirty_pages_ratelimited() to be called which on systems with little memory actually tries to go and balance the dirty pages which tries to take the s_umount semaphore but because we are still in fill_super() across which the VFS holds s_umount for writing this results in a deadlock. We now do the dirty work by hand by submitting individual buffers. This has the annoying "feature" that mounting can take a few seconds if the journal is large as we have clear it all. One day someone should improve on this by deferring the journal clearing to a helper kernel thread so it can be done in the background but I don't have time for this at the moment and the current solution works fine so I am leaving it like this for now. Signed-off-by: Anton Altaparmakov <aia21@cantab.net> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/ntfs/aops.c')
-rw-r--r--fs/ntfs/aops.c22
1 files changed, 11 insertions, 11 deletions
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
index 6e5c2534f4bc..cfdc7900d271 100644
--- a/fs/ntfs/aops.c
+++ b/fs/ntfs/aops.c
@@ -2,7 +2,7 @@
2 * aops.c - NTFS kernel address space operations and page cache handling. 2 * aops.c - NTFS kernel address space operations and page cache handling.
3 * Part of the Linux-NTFS project. 3 * Part of the Linux-NTFS project.
4 * 4 *
5 * Copyright (c) 2001-2006 Anton Altaparmakov 5 * Copyright (c) 2001-2007 Anton Altaparmakov
6 * Copyright (c) 2002 Richard Russon 6 * Copyright (c) 2002 Richard Russon
7 * 7 *
8 * This program/include file is free software; you can redistribute it and/or 8 * This program/include file is free software; you can redistribute it and/or
@@ -396,7 +396,7 @@ static int ntfs_readpage(struct file *file, struct page *page)
396 loff_t i_size; 396 loff_t i_size;
397 struct inode *vi; 397 struct inode *vi;
398 ntfs_inode *ni, *base_ni; 398 ntfs_inode *ni, *base_ni;
399 u8 *kaddr; 399 u8 *addr;
400 ntfs_attr_search_ctx *ctx; 400 ntfs_attr_search_ctx *ctx;
401 MFT_RECORD *mrec; 401 MFT_RECORD *mrec;
402 unsigned long flags; 402 unsigned long flags;
@@ -491,15 +491,15 @@ retry_readpage:
491 /* Race with shrinking truncate. */ 491 /* Race with shrinking truncate. */
492 attr_len = i_size; 492 attr_len = i_size;
493 } 493 }
494 kaddr = kmap_atomic(page, KM_USER0); 494 addr = kmap_atomic(page, KM_USER0);
495 /* Copy the data to the page. */ 495 /* Copy the data to the page. */
496 memcpy(kaddr, (u8*)ctx->attr + 496 memcpy(addr, (u8*)ctx->attr +
497 le16_to_cpu(ctx->attr->data.resident.value_offset), 497 le16_to_cpu(ctx->attr->data.resident.value_offset),
498 attr_len); 498 attr_len);
499 /* Zero the remainder of the page. */ 499 /* Zero the remainder of the page. */
500 memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); 500 memset(addr + attr_len, 0, PAGE_CACHE_SIZE - attr_len);
501 flush_dcache_page(page); 501 flush_dcache_page(page);
502 kunmap_atomic(kaddr, KM_USER0); 502 kunmap_atomic(addr, KM_USER0);
503put_unm_err_out: 503put_unm_err_out:
504 ntfs_attr_put_search_ctx(ctx); 504 ntfs_attr_put_search_ctx(ctx);
505unm_err_out: 505unm_err_out:
@@ -1344,7 +1344,7 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
1344 loff_t i_size; 1344 loff_t i_size;
1345 struct inode *vi = page->mapping->host; 1345 struct inode *vi = page->mapping->host;
1346 ntfs_inode *base_ni = NULL, *ni = NTFS_I(vi); 1346 ntfs_inode *base_ni = NULL, *ni = NTFS_I(vi);
1347 char *kaddr; 1347 char *addr;
1348 ntfs_attr_search_ctx *ctx = NULL; 1348 ntfs_attr_search_ctx *ctx = NULL;
1349 MFT_RECORD *m = NULL; 1349 MFT_RECORD *m = NULL;
1350 u32 attr_len; 1350 u32 attr_len;
@@ -1484,14 +1484,14 @@ retry_writepage:
1484 /* Shrinking cannot fail. */ 1484 /* Shrinking cannot fail. */
1485 BUG_ON(err); 1485 BUG_ON(err);
1486 } 1486 }
1487 kaddr = kmap_atomic(page, KM_USER0); 1487 addr = kmap_atomic(page, KM_USER0);
1488 /* Copy the data from the page to the mft record. */ 1488 /* Copy the data from the page to the mft record. */
1489 memcpy((u8*)ctx->attr + 1489 memcpy((u8*)ctx->attr +
1490 le16_to_cpu(ctx->attr->data.resident.value_offset), 1490 le16_to_cpu(ctx->attr->data.resident.value_offset),
1491 kaddr, attr_len); 1491 addr, attr_len);
1492 /* Zero out of bounds area in the page cache page. */ 1492 /* Zero out of bounds area in the page cache page. */
1493 memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); 1493 memset(addr + attr_len, 0, PAGE_CACHE_SIZE - attr_len);
1494 kunmap_atomic(kaddr, KM_USER0); 1494 kunmap_atomic(addr, KM_USER0);
1495 flush_dcache_page(page); 1495 flush_dcache_page(page);
1496 flush_dcache_mft_record_page(ctx->ntfs_ino); 1496 flush_dcache_mft_record_page(ctx->ntfs_ino);
1497 /* We are done with the page. */ 1497 /* We are done with the page. */