diff options
author | Anton Altaparmakov <aia21@cantab.net> | 2005-02-15 05:08:43 -0500 |
---|---|---|
committer | Anton Altaparmakov <aia21@cantab.net> | 2005-05-05 05:56:31 -0400 |
commit | b6ad6c52fe36ab35d0fe28c064f59de2ba670c2a (patch) | |
tree | d888c28a2c3c7fa733045dc7dc9c9bc7f157bf4a /fs/ntfs/attrib.c | |
parent | 1a0df15acdae065789446aca83021c72b71db9a5 (diff) |
NTFS: - Split ntfs_map_runlist() into ntfs_map_runlist() and a non-locking
helper ntfs_map_runlist_nolock() which is used by ntfs_map_runlist().
This allows us to map runlist fragments with the runlist lock already
held without having to drop and reacquire it around the call. Adapt
all callers.
- Change ntfs_find_vcn() to ntfs_find_vcn_nolock() which takes a locked
runlist. This allows us to find runlist elements with the runlist
lock already held without having to drop and reacquire it around the
call. Adapt all callers.
Signed-off-by: Anton Altaparmakov <aia21@cantab.net>
Diffstat (limited to 'fs/ntfs/attrib.c')
-rw-r--r-- | fs/ntfs/attrib.c | 107 |
1 files changed, 62 insertions, 45 deletions
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 7d668466dcd7..7a16f7ca76d8 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /** | 1 | /** |
2 | * attrib.c - NTFS attribute operations. Part of the Linux-NTFS project. | 2 | * attrib.c - NTFS attribute operations. Part of the Linux-NTFS project. |
3 | * | 3 | * |
4 | * Copyright (c) 2001-2004 Anton Altaparmakov | 4 | * Copyright (c) 2001-2005 Anton Altaparmakov |
5 | * Copyright (c) 2002 Richard Russon | 5 | * Copyright (c) 2002 Richard Russon |
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 |
@@ -30,7 +30,7 @@ | |||
30 | #include "types.h" | 30 | #include "types.h" |
31 | 31 | ||
32 | /** | 32 | /** |
33 | * ntfs_map_runlist - map (a part of) a runlist of an ntfs inode | 33 | * ntfs_map_runlist_nolock - map (a part of) a runlist of an ntfs inode |
34 | * @ni: ntfs inode for which to map (part of) a runlist | 34 | * @ni: ntfs inode for which to map (part of) a runlist |
35 | * @vcn: map runlist part containing this vcn | 35 | * @vcn: map runlist part containing this vcn |
36 | * | 36 | * |
@@ -38,24 +38,23 @@ | |||
38 | * | 38 | * |
39 | * Return 0 on success and -errno on error. | 39 | * Return 0 on success and -errno on error. |
40 | * | 40 | * |
41 | * Locking: - The runlist must be unlocked on entry and is unlocked on return. | 41 | * Locking: - The runlist must be locked for writing. |
42 | * - This function takes the lock for writing and modifies the runlist. | 42 | * - This function modifies the runlist. |
43 | */ | 43 | */ |
44 | int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) | 44 | int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) |
45 | { | 45 | { |
46 | ntfs_inode *base_ni; | 46 | ntfs_inode *base_ni; |
47 | ntfs_attr_search_ctx *ctx; | ||
48 | MFT_RECORD *mrec; | 47 | MFT_RECORD *mrec; |
48 | ntfs_attr_search_ctx *ctx; | ||
49 | runlist_element *rl; | ||
49 | int err = 0; | 50 | int err = 0; |
50 | 51 | ||
51 | ntfs_debug("Mapping runlist part containing vcn 0x%llx.", | 52 | ntfs_debug("Mapping runlist part containing vcn 0x%llx.", |
52 | (unsigned long long)vcn); | 53 | (unsigned long long)vcn); |
53 | |||
54 | if (!NInoAttr(ni)) | 54 | if (!NInoAttr(ni)) |
55 | base_ni = ni; | 55 | base_ni = ni; |
56 | else | 56 | else |
57 | base_ni = ni->ext.base_ntfs_ino; | 57 | base_ni = ni->ext.base_ntfs_ino; |
58 | |||
59 | mrec = map_mft_record(base_ni); | 58 | mrec = map_mft_record(base_ni); |
60 | if (IS_ERR(mrec)) | 59 | if (IS_ERR(mrec)) |
61 | return PTR_ERR(mrec); | 60 | return PTR_ERR(mrec); |
@@ -66,15 +65,7 @@ int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) | |||
66 | } | 65 | } |
67 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | 66 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, |
68 | CASE_SENSITIVE, vcn, NULL, 0, ctx); | 67 | CASE_SENSITIVE, vcn, NULL, 0, ctx); |
69 | if (unlikely(err)) | 68 | if (likely(!err)) { |
70 | goto put_err_out; | ||
71 | |||
72 | down_write(&ni->runlist.lock); | ||
73 | /* Make sure someone else didn't do the work while we were sleeping. */ | ||
74 | if (likely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) <= | ||
75 | LCN_RL_NOT_MAPPED)) { | ||
76 | runlist_element *rl; | ||
77 | |||
78 | rl = ntfs_mapping_pairs_decompress(ni->vol, ctx->attr, | 69 | rl = ntfs_mapping_pairs_decompress(ni->vol, ctx->attr, |
79 | ni->runlist.rl); | 70 | ni->runlist.rl); |
80 | if (IS_ERR(rl)) | 71 | if (IS_ERR(rl)) |
@@ -82,9 +73,6 @@ int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) | |||
82 | else | 73 | else |
83 | ni->runlist.rl = rl; | 74 | ni->runlist.rl = rl; |
84 | } | 75 | } |
85 | up_write(&ni->runlist.lock); | ||
86 | |||
87 | put_err_out: | ||
88 | ntfs_attr_put_search_ctx(ctx); | 76 | ntfs_attr_put_search_ctx(ctx); |
89 | err_out: | 77 | err_out: |
90 | unmap_mft_record(base_ni); | 78 | unmap_mft_record(base_ni); |
@@ -92,17 +80,45 @@ err_out: | |||
92 | } | 80 | } |
93 | 81 | ||
94 | /** | 82 | /** |
95 | * ntfs_find_vcn - find a vcn in the runlist described by an ntfs inode | 83 | * ntfs_map_runlist - map (a part of) a runlist of an ntfs inode |
96 | * @ni: ntfs inode describing the runlist to search | 84 | * @ni: ntfs inode for which to map (part of) a runlist |
97 | * @vcn: vcn to find | 85 | * @vcn: map runlist part containing this vcn |
98 | * @need_write: if false, lock for reading and if true, lock for writing | 86 | * |
87 | * Map the part of a runlist containing the @vcn of the ntfs inode @ni. | ||
88 | * | ||
89 | * Return 0 on success and -errno on error. | ||
90 | * | ||
91 | * Locking: - The runlist must be unlocked on entry and is unlocked on return. | ||
92 | * - This function takes the runlist lock for writing and modifies the | ||
93 | * runlist. | ||
94 | */ | ||
95 | int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) | ||
96 | { | ||
97 | int err = 0; | ||
98 | |||
99 | down_write(&ni->runlist.lock); | ||
100 | /* Make sure someone else didn't do the work while we were sleeping. */ | ||
101 | if (likely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) <= | ||
102 | LCN_RL_NOT_MAPPED)) | ||
103 | err = ntfs_map_runlist_nolock(ni, vcn); | ||
104 | up_write(&ni->runlist.lock); | ||
105 | return err; | ||
106 | } | ||
107 | |||
108 | /** | ||
109 | * ntfs_find_vcn_nolock - find a vcn in the runlist described by an ntfs inode | ||
110 | * @ni: ntfs inode describing the runlist to search | ||
111 | * @vcn: vcn to find | ||
112 | * @write_locked: true if the runlist is locked for writing | ||
99 | * | 113 | * |
100 | * Find the virtual cluster number @vcn in the runlist described by the ntfs | 114 | * Find the virtual cluster number @vcn in the runlist described by the ntfs |
101 | * inode @ni and return the address of the runlist element containing the @vcn. | 115 | * inode @ni and return the address of the runlist element containing the @vcn. |
102 | * The runlist is left locked and the caller has to unlock it. If @need_write | 116 | * The runlist is left locked and the caller has to unlock it. In the error |
103 | * is true, the runlist is locked for writing and if @need_write is false, the | 117 | * case, the runlist is left in the same locking state as on entry. |
104 | * runlist is locked for reading. In the error case, the runlist is not left | 118 | * |
105 | * locked. | 119 | * Note if @write_locked is FALSE the lock may be dropped inside the function |
120 | * so you cannot rely on the runlist still being the same when this function | ||
121 | * returns. | ||
106 | * | 122 | * |
107 | * Note you need to distinguish between the lcn of the returned runlist element | 123 | * Note you need to distinguish between the lcn of the returned runlist element |
108 | * being >= 0 and LCN_HOLE. In the later case you have to return zeroes on | 124 | * being >= 0 and LCN_HOLE. In the later case you have to return zeroes on |
@@ -124,28 +140,24 @@ err_out: | |||
124 | * true, it is locked for writing. Otherwise is is locked for | 140 | * true, it is locked for writing. Otherwise is is locked for |
125 | * reading. | 141 | * reading. |
126 | */ | 142 | */ |
127 | runlist_element *ntfs_find_vcn(ntfs_inode *ni, const VCN vcn, | 143 | runlist_element *ntfs_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, |
128 | const BOOL need_write) | 144 | const BOOL write_locked) |
129 | { | 145 | { |
130 | runlist_element *rl; | 146 | runlist_element *rl; |
131 | int err = 0; | 147 | int err = 0; |
132 | BOOL is_retry = FALSE; | 148 | BOOL is_retry = FALSE; |
133 | 149 | ||
134 | ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, lock for %sing.", | 150 | ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.", |
135 | ni->mft_no, (unsigned long long)vcn, | 151 | ni->mft_no, (unsigned long long)vcn, |
136 | !need_write ? "read" : "writ"); | 152 | write_locked ? "write" : "read"); |
137 | BUG_ON(!ni); | 153 | BUG_ON(!ni); |
138 | BUG_ON(!NInoNonResident(ni)); | 154 | BUG_ON(!NInoNonResident(ni)); |
139 | BUG_ON(vcn < 0); | 155 | BUG_ON(vcn < 0); |
140 | lock_retry_remap: | 156 | retry_remap: |
141 | if (!need_write) | ||
142 | down_read(&ni->runlist.lock); | ||
143 | else | ||
144 | down_write(&ni->runlist.lock); | ||
145 | rl = ni->runlist.rl; | 157 | rl = ni->runlist.rl; |
146 | if (likely(rl && vcn >= rl[0].vcn)) { | 158 | if (likely(rl && vcn >= rl[0].vcn)) { |
147 | while (likely(rl->length)) { | 159 | while (likely(rl->length)) { |
148 | if (likely(vcn < rl[1].vcn)) { | 160 | if (unlikely(vcn < rl[1].vcn)) { |
149 | if (likely(rl->lcn >= LCN_HOLE)) { | 161 | if (likely(rl->lcn >= LCN_HOLE)) { |
150 | ntfs_debug("Done."); | 162 | ntfs_debug("Done."); |
151 | return rl; | 163 | return rl; |
@@ -161,19 +173,23 @@ lock_retry_remap: | |||
161 | err = -EIO; | 173 | err = -EIO; |
162 | } | 174 | } |
163 | } | 175 | } |
164 | if (!need_write) | ||
165 | up_read(&ni->runlist.lock); | ||
166 | else | ||
167 | up_write(&ni->runlist.lock); | ||
168 | if (!err && !is_retry) { | 176 | if (!err && !is_retry) { |
169 | /* | 177 | /* |
170 | * The @vcn is in an unmapped region, map the runlist and | 178 | * The @vcn is in an unmapped region, map the runlist and |
171 | * retry. | 179 | * retry. |
172 | */ | 180 | */ |
173 | err = ntfs_map_runlist(ni, vcn); | 181 | if (!write_locked) { |
182 | up_read(&ni->runlist.lock); | ||
183 | down_write(&ni->runlist.lock); | ||
184 | } | ||
185 | err = ntfs_map_runlist_nolock(ni, vcn); | ||
186 | if (!write_locked) { | ||
187 | up_write(&ni->runlist.lock); | ||
188 | down_read(&ni->runlist.lock); | ||
189 | } | ||
174 | if (likely(!err)) { | 190 | if (likely(!err)) { |
175 | is_retry = TRUE; | 191 | is_retry = TRUE; |
176 | goto lock_retry_remap; | 192 | goto retry_remap; |
177 | } | 193 | } |
178 | /* | 194 | /* |
179 | * -EINVAL and -ENOENT coming from a failed mapping attempt are | 195 | * -EINVAL and -ENOENT coming from a failed mapping attempt are |
@@ -184,7 +200,8 @@ lock_retry_remap: | |||
184 | err = -EIO; | 200 | err = -EIO; |
185 | } else if (!err) | 201 | } else if (!err) |
186 | err = -EIO; | 202 | err = -EIO; |
187 | ntfs_error(ni->vol->sb, "Failed with error code %i.", err); | 203 | if (err != -ENOENT) |
204 | ntfs_error(ni->vol->sb, "Failed with error code %i.", err); | ||
188 | return ERR_PTR(err); | 205 | return ERR_PTR(err); |
189 | } | 206 | } |
190 | 207 | ||