aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAnton Altaparmakov <aia21@cantab.net>2005-09-23 06:24:28 -0400
committerAnton Altaparmakov <aia21@cantab.net>2005-09-23 06:24:28 -0400
commit715dc636b64b57aee7aee7e8b5bf4f5267a6df48 (patch)
tree967c70011391cb38e232015902189623eb9c5193 /fs
parent91fbc6edfa7086b5fcdb74ea82ab747104541f1f (diff)
NTFS: Change ntfs_cluster_free() to require a write locked runlist on entry
since we otherwise get into a lock reversal deadlock if a read locked runlist is passed in. In the process also change it to take an ntfs inode instead of a vfs inode as parameter. Signed-off-by: Anton Altaparmakov <aia21@cantab.net>
Diffstat (limited to 'fs')
-rw-r--r--fs/ntfs/ChangeLog4
-rw-r--r--fs/ntfs/Makefile2
-rw-r--r--fs/ntfs/lcnalloc.c31
-rw-r--r--fs/ntfs/lcnalloc.h27
-rw-r--r--fs/ntfs/mft.c2
5 files changed, 32 insertions, 34 deletions
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
index ee8665f62a6..574896f27c3 100644
--- a/fs/ntfs/ChangeLog
+++ b/fs/ntfs/ChangeLog
@@ -25,6 +25,10 @@ ToDo/Notes:
252.1.25-WIP 252.1.25-WIP
26 26
27 - Fix sparse warnings that have crept in over time. 27 - Fix sparse warnings that have crept in over time.
28 - Change ntfs_cluster_free() to require a write locked runlist on entry
29 since we otherwise get into a lock reversal deadlock if a read locked
30 runlist is passed in. In the process also change it to take an ntfs
31 inode instead of a vfs inode as parameter.
28 32
292.1.24 - Lots of bug fixes and support more clean journal states. 332.1.24 - Lots of bug fixes and support more clean journal states.
30 34
diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile
index 894b2b876d3..a3ce2c0e7dd 100644
--- a/fs/ntfs/Makefile
+++ b/fs/ntfs/Makefile
@@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
6 index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ 6 index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
7 unistr.o upcase.o 7 unistr.o upcase.o
8 8
9EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.24\" 9EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.25-WIP\"
10 10
11ifeq ($(CONFIG_NTFS_DEBUG),y) 11ifeq ($(CONFIG_NTFS_DEBUG),y)
12EXTRA_CFLAGS += -DDEBUG 12EXTRA_CFLAGS += -DDEBUG
diff --git a/fs/ntfs/lcnalloc.c b/fs/ntfs/lcnalloc.c
index 7b593429068..5af3bf0b7ee 100644
--- a/fs/ntfs/lcnalloc.c
+++ b/fs/ntfs/lcnalloc.c
@@ -779,14 +779,13 @@ out:
779 779
780/** 780/**
781 * __ntfs_cluster_free - free clusters on an ntfs volume 781 * __ntfs_cluster_free - free clusters on an ntfs volume
782 * @vi: vfs inode whose runlist describes the clusters to free 782 * @ni: ntfs inode whose runlist describes the clusters to free
783 * @start_vcn: vcn in the runlist of @vi at which to start freeing clusters 783 * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters
784 * @count: number of clusters to free or -1 for all clusters 784 * @count: number of clusters to free or -1 for all clusters
785 * @write_locked: true if the runlist is locked for writing
786 * @is_rollback: true if this is a rollback operation 785 * @is_rollback: true if this is a rollback operation
787 * 786 *
788 * Free @count clusters starting at the cluster @start_vcn in the runlist 787 * Free @count clusters starting at the cluster @start_vcn in the runlist
789 * described by the vfs inode @vi. 788 * described by the vfs inode @ni.
790 * 789 *
791 * If @count is -1, all clusters from @start_vcn to the end of the runlist are 790 * If @count is -1, all clusters from @start_vcn to the end of the runlist are
792 * deallocated. Thus, to completely free all clusters in a runlist, use 791 * deallocated. Thus, to completely free all clusters in a runlist, use
@@ -801,31 +800,28 @@ out:
801 * Return the number of deallocated clusters (not counting sparse ones) on 800 * Return the number of deallocated clusters (not counting sparse ones) on
802 * success and -errno on error. 801 * success and -errno on error.
803 * 802 *
804 * Locking: - The runlist described by @vi must be locked on entry and is 803 * Locking: - The runlist described by @ni must be locked for writing on entry
805 * locked on return. Note if the runlist is locked for reading the 804 * and is locked on return. Note the runlist may be modified when
806 * lock may be dropped and reacquired. Note the runlist may be 805 * needed runlist fragments need to be mapped.
807 * modified when needed runlist fragments need to be mapped.
808 * - The volume lcn bitmap must be unlocked on entry and is unlocked 806 * - The volume lcn bitmap must be unlocked on entry and is unlocked
809 * on return. 807 * on return.
810 * - This function takes the volume lcn bitmap lock for writing and 808 * - This function takes the volume lcn bitmap lock for writing and
811 * modifies the bitmap contents. 809 * modifies the bitmap contents.
812 */ 810 */
813s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count, 811s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count,
814 const BOOL write_locked, const BOOL is_rollback) 812 const BOOL is_rollback)
815{ 813{
816 s64 delta, to_free, total_freed, real_freed; 814 s64 delta, to_free, total_freed, real_freed;
817 ntfs_inode *ni;
818 ntfs_volume *vol; 815 ntfs_volume *vol;
819 struct inode *lcnbmp_vi; 816 struct inode *lcnbmp_vi;
820 runlist_element *rl; 817 runlist_element *rl;
821 int err; 818 int err;
822 819
823 BUG_ON(!vi); 820 BUG_ON(!ni);
824 ntfs_debug("Entering for i_ino 0x%lx, start_vcn 0x%llx, count " 821 ntfs_debug("Entering for i_ino 0x%lx, start_vcn 0x%llx, count "
825 "0x%llx.%s", vi->i_ino, (unsigned long long)start_vcn, 822 "0x%llx.%s", ni->mft_no, (unsigned long long)start_vcn,
826 (unsigned long long)count, 823 (unsigned long long)count,
827 is_rollback ? " (rollback)" : ""); 824 is_rollback ? " (rollback)" : "");
828 ni = NTFS_I(vi);
829 vol = ni->vol; 825 vol = ni->vol;
830 lcnbmp_vi = vol->lcnbmp_ino; 826 lcnbmp_vi = vol->lcnbmp_ino;
831 BUG_ON(!lcnbmp_vi); 827 BUG_ON(!lcnbmp_vi);
@@ -843,7 +839,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
843 839
844 total_freed = real_freed = 0; 840 total_freed = real_freed = 0;
845 841
846 rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, write_locked); 842 rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, TRUE);
847 if (IS_ERR(rl)) { 843 if (IS_ERR(rl)) {
848 if (!is_rollback) 844 if (!is_rollback)
849 ntfs_error(vol->sb, "Failed to find first runlist " 845 ntfs_error(vol->sb, "Failed to find first runlist "
@@ -897,7 +893,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
897 893
898 /* Attempt to map runlist. */ 894 /* Attempt to map runlist. */
899 vcn = rl->vcn; 895 vcn = rl->vcn;
900 rl = ntfs_attr_find_vcn_nolock(ni, vcn, write_locked); 896 rl = ntfs_attr_find_vcn_nolock(ni, vcn, TRUE);
901 if (IS_ERR(rl)) { 897 if (IS_ERR(rl)) {
902 err = PTR_ERR(rl); 898 err = PTR_ERR(rl);
903 if (!is_rollback) 899 if (!is_rollback)
@@ -965,8 +961,7 @@ err_out:
965 * If rollback fails, set the volume errors flag, emit an error 961 * If rollback fails, set the volume errors flag, emit an error
966 * message, and return the error code. 962 * message, and return the error code.
967 */ 963 */
968 delta = __ntfs_cluster_free(vi, start_vcn, total_freed, write_locked, 964 delta = __ntfs_cluster_free(ni, start_vcn, total_freed, TRUE);
969 TRUE);
970 if (delta < 0) { 965 if (delta < 0) {
971 ntfs_error(vol->sb, "Failed to rollback (error %i). Leaving " 966 ntfs_error(vol->sb, "Failed to rollback (error %i). Leaving "
972 "inconsistent metadata! Unmount and run " 967 "inconsistent metadata! Unmount and run "
diff --git a/fs/ntfs/lcnalloc.h b/fs/ntfs/lcnalloc.h
index e4d7fb98d68..a6a8827882e 100644
--- a/fs/ntfs/lcnalloc.h
+++ b/fs/ntfs/lcnalloc.h
@@ -2,7 +2,7 @@
2 * lcnalloc.h - Exports for NTFS kernel cluster (de)allocation. Part of the 2 * lcnalloc.h - Exports for NTFS kernel cluster (de)allocation. Part of the
3 * Linux-NTFS project. 3 * Linux-NTFS project.
4 * 4 *
5 * Copyright (c) 2004 Anton Altaparmakov 5 * Copyright (c) 2004-2005 Anton Altaparmakov
6 * 6 *
7 * This program/include file is free software; you can redistribute it and/or 7 * This program/include file is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as published 8 * modify it under the terms of the GNU General Public License as published
@@ -28,6 +28,7 @@
28#include <linux/fs.h> 28#include <linux/fs.h>
29 29
30#include "types.h" 30#include "types.h"
31#include "inode.h"
31#include "runlist.h" 32#include "runlist.h"
32#include "volume.h" 33#include "volume.h"
33 34
@@ -42,18 +43,17 @@ extern runlist_element *ntfs_cluster_alloc(ntfs_volume *vol,
42 const VCN start_vcn, const s64 count, const LCN start_lcn, 43 const VCN start_vcn, const s64 count, const LCN start_lcn,
43 const NTFS_CLUSTER_ALLOCATION_ZONES zone); 44 const NTFS_CLUSTER_ALLOCATION_ZONES zone);
44 45
45extern s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, 46extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn,
46 s64 count, const BOOL write_locked, const BOOL is_rollback); 47 s64 count, const BOOL is_rollback);
47 48
48/** 49/**
49 * ntfs_cluster_free - free clusters on an ntfs volume 50 * ntfs_cluster_free - free clusters on an ntfs volume
50 * @vi: vfs inode whose runlist describes the clusters to free 51 * @ni: ntfs inode whose runlist describes the clusters to free
51 * @start_vcn: vcn in the runlist of @vi at which to start freeing clusters 52 * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters
52 * @count: number of clusters to free or -1 for all clusters 53 * @count: number of clusters to free or -1 for all clusters
53 * @write_locked: true if the runlist is locked for writing
54 * 54 *
55 * Free @count clusters starting at the cluster @start_vcn in the runlist 55 * Free @count clusters starting at the cluster @start_vcn in the runlist
56 * described by the vfs inode @vi. 56 * described by the ntfs inode @ni.
57 * 57 *
58 * If @count is -1, all clusters from @start_vcn to the end of the runlist are 58 * If @count is -1, all clusters from @start_vcn to the end of the runlist are
59 * deallocated. Thus, to completely free all clusters in a runlist, use 59 * deallocated. Thus, to completely free all clusters in a runlist, use
@@ -65,19 +65,18 @@ extern s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn,
65 * Return the number of deallocated clusters (not counting sparse ones) on 65 * Return the number of deallocated clusters (not counting sparse ones) on
66 * success and -errno on error. 66 * success and -errno on error.
67 * 67 *
68 * Locking: - The runlist described by @vi must be locked on entry and is 68 * Locking: - The runlist described by @ni must be locked for writing on entry
69 * locked on return. Note if the runlist is locked for reading the 69 * and is locked on return. Note the runlist may be modified when
70 * lock may be dropped and reacquired. Note the runlist may be 70 * needed runlist fragments need to be mapped.
71 * modified when needed runlist fragments need to be mapped.
72 * - The volume lcn bitmap must be unlocked on entry and is unlocked 71 * - The volume lcn bitmap must be unlocked on entry and is unlocked
73 * on return. 72 * on return.
74 * - This function takes the volume lcn bitmap lock for writing and 73 * - This function takes the volume lcn bitmap lock for writing and
75 * modifies the bitmap contents. 74 * modifies the bitmap contents.
76 */ 75 */
77static inline s64 ntfs_cluster_free(struct inode *vi, const VCN start_vcn, 76static inline s64 ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn,
78 s64 count, const BOOL write_locked) 77 s64 count)
79{ 78{
80 return __ntfs_cluster_free(vi, start_vcn, count, write_locked, FALSE); 79 return __ntfs_cluster_free(ni, start_vcn, count, FALSE);
81} 80}
82 81
83extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, 82extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol,
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c
index 2c32b84385a..247586d1d5d 100644
--- a/fs/ntfs/mft.c
+++ b/fs/ntfs/mft.c
@@ -1953,7 +1953,7 @@ restore_undo_alloc:
1953 a = ctx->attr; 1953 a = ctx->attr;
1954 a->data.non_resident.highest_vcn = cpu_to_sle64(old_last_vcn - 1); 1954 a->data.non_resident.highest_vcn = cpu_to_sle64(old_last_vcn - 1);
1955undo_alloc: 1955undo_alloc:
1956 if (ntfs_cluster_free(vol->mft_ino, old_last_vcn, -1, TRUE) < 0) { 1956 if (ntfs_cluster_free(mft_ni, old_last_vcn, -1) < 0) {
1957 ntfs_error(vol->sb, "Failed to free clusters from mft data " 1957 ntfs_error(vol->sb, "Failed to free clusters from mft data "
1958 "attribute.%s", es); 1958 "attribute.%s", es);
1959 NVolSetErrors(vol); 1959 NVolSetErrors(vol);