diff options
Diffstat (limited to 'fs/ntfs/mft.c')
-rw-r--r-- | fs/ntfs/mft.c | 29 |
1 files changed, 19 insertions, 10 deletions
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 3d0ba8e60adc..ac9ff39aa834 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c | |||
@@ -948,20 +948,23 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no, | |||
948 | na.name_len = 0; | 948 | na.name_len = 0; |
949 | na.type = AT_UNUSED; | 949 | na.type = AT_UNUSED; |
950 | /* | 950 | /* |
951 | * For inode 0, i.e. $MFT itself, we cannot use ilookup5() from here or | 951 | * Optimize inode 0, i.e. $MFT itself, since we have it in memory and |
952 | * we deadlock because the inode is already locked by the kernel | 952 | * we get here for it rather often. |
953 | * (fs/fs-writeback.c::__sync_single_inode()) and ilookup5() waits | ||
954 | * until the inode is unlocked before returning it and it never gets | ||
955 | * unlocked because ntfs_should_write_mft_record() never returns. )-: | ||
956 | * Fortunately, we have inode 0 pinned in icache for the duration of | ||
957 | * the mount so we can access it directly. | ||
958 | */ | 953 | */ |
959 | if (!mft_no) { | 954 | if (!mft_no) { |
960 | /* Balance the below iput(). */ | 955 | /* Balance the below iput(). */ |
961 | vi = igrab(mft_vi); | 956 | vi = igrab(mft_vi); |
962 | BUG_ON(vi != mft_vi); | 957 | BUG_ON(vi != mft_vi); |
963 | } else | 958 | } else { |
964 | vi = ilookup5(sb, mft_no, (test_t)ntfs_test_inode, &na); | 959 | /* |
960 | * Have to use ilookup5_nowait() since ilookup5() waits for the | ||
961 | * inode lock which causes ntfs to deadlock when a concurrent | ||
962 | * inode write via the inode dirty code paths and the page | ||
963 | * dirty code path of the inode dirty code path when writing | ||
964 | * $MFT occurs. | ||
965 | */ | ||
966 | vi = ilookup5_nowait(sb, mft_no, (test_t)ntfs_test_inode, &na); | ||
967 | } | ||
965 | if (vi) { | 968 | if (vi) { |
966 | ntfs_debug("Base inode 0x%lx is in icache.", mft_no); | 969 | ntfs_debug("Base inode 0x%lx is in icache.", mft_no); |
967 | /* The inode is in icache. */ | 970 | /* The inode is in icache. */ |
@@ -1016,7 +1019,13 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no, | |||
1016 | na.mft_no = MREF_LE(m->base_mft_record); | 1019 | na.mft_no = MREF_LE(m->base_mft_record); |
1017 | ntfs_debug("Mft record 0x%lx is an extent record. Looking for base " | 1020 | ntfs_debug("Mft record 0x%lx is an extent record. Looking for base " |
1018 | "inode 0x%lx in icache.", mft_no, na.mft_no); | 1021 | "inode 0x%lx in icache.", mft_no, na.mft_no); |
1019 | vi = ilookup5(sb, na.mft_no, (test_t)ntfs_test_inode, &na); | 1022 | if (!na.mft_no) { |
1023 | /* Balance the below iput(). */ | ||
1024 | vi = igrab(mft_vi); | ||
1025 | BUG_ON(vi != mft_vi); | ||
1026 | } else | ||
1027 | vi = ilookup5_nowait(sb, na.mft_no, (test_t)ntfs_test_inode, | ||
1028 | &na); | ||
1020 | if (!vi) { | 1029 | if (!vi) { |
1021 | /* | 1030 | /* |
1022 | * The base inode is not in icache, write this extent mft | 1031 | * The base inode is not in icache, write this extent mft |