diff options
Diffstat (limited to 'fs/ntfs')
-rw-r--r-- | fs/ntfs/ChangeLog | 6 | ||||
-rw-r--r-- | fs/ntfs/attrib.c | 87 | ||||
-rw-r--r-- | fs/ntfs/attrib.h | 5 |
3 files changed, 95 insertions, 3 deletions
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 868871cb9c6e..4af6ae6ff12b 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog | |||
@@ -88,8 +88,10 @@ ToDo/Notes: | |||
88 | checked and set in the ntfs inode as done for compressed files and | 88 | checked and set in the ntfs inode as done for compressed files and |
89 | the compressed size needs to be used for vfs inode->i_blocks instead | 89 | the compressed size needs to be used for vfs inode->i_blocks instead |
90 | of the allocated size, again, as done for compressed files. | 90 | of the allocated size, again, as done for compressed files. |
91 | - Add AT_EA in addition to AT_DATA to whitelist for being allowed to | 91 | - Add AT_EA in addition to AT_DATA to whitelist for being allowed to be |
92 | be non-resident in fs/ntfs/attrib.c::ntfs_attr_can_be_non_resident(). | 92 | non-resident in fs/ntfs/attrib.c::ntfs_attr_can_be_non_resident(). |
93 | - Add fs/ntfs/attrib.c::ntfs_attr_vcn_to_lcn_nolock() used by the new | ||
94 | write code. | ||
93 | 95 | ||
94 | 2.1.22 - Many bug and race fixes and error handling improvements. | 96 | 2.1.22 - Many bug and race fixes and error handling improvements. |
95 | 97 | ||
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index fa464fce2261..1610f1cd2862 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c | |||
@@ -106,6 +106,93 @@ int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) | |||
106 | } | 106 | } |
107 | 107 | ||
108 | /** | 108 | /** |
109 | * ntfs_attr_vcn_to_lcn_nolock - convert a vcn into a lcn given an ntfs inode | ||
110 | * @ni: ntfs inode of the attribute whose runlist to search | ||
111 | * @vcn: vcn to convert | ||
112 | * @write_locked: true if the runlist is locked for writing | ||
113 | * | ||
114 | * Find the virtual cluster number @vcn in the runlist of the ntfs attribute | ||
115 | * described by the ntfs inode @ni and return the corresponding logical cluster | ||
116 | * number (lcn). | ||
117 | * | ||
118 | * If the @vcn is not mapped yet, the attempt is made to map the attribute | ||
119 | * extent containing the @vcn and the vcn to lcn conversion is retried. | ||
120 | * | ||
121 | * If @write_locked is true the caller has locked the runlist for writing and | ||
122 | * if false for reading. | ||
123 | * | ||
124 | * Since lcns must be >= 0, we use negative return codes with special meaning: | ||
125 | * | ||
126 | * Return code Meaning / Description | ||
127 | * ========================================== | ||
128 | * LCN_HOLE Hole / not allocated on disk. | ||
129 | * LCN_ENOENT There is no such vcn in the runlist, i.e. @vcn is out of bounds. | ||
130 | * LCN_ENOMEM Not enough memory to map runlist. | ||
131 | * LCN_EIO Critical error (runlist/file is corrupt, i/o error, etc). | ||
132 | * | ||
133 | * Locking: - The runlist must be locked on entry and is left locked on return. | ||
134 | * - If @write_locked is FALSE, i.e. the runlist is locked for reading, | ||
135 | * the lock may be dropped inside the function so you cannot rely on | ||
136 | * the runlist still being the same when this function returns. | ||
137 | */ | ||
138 | LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, | ||
139 | const BOOL write_locked) | ||
140 | { | ||
141 | LCN lcn; | ||
142 | BOOL is_retry = FALSE; | ||
143 | |||
144 | ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.", | ||
145 | ni->mft_no, (unsigned long long)vcn, | ||
146 | write_locked ? "write" : "read"); | ||
147 | BUG_ON(!ni); | ||
148 | BUG_ON(!NInoNonResident(ni)); | ||
149 | BUG_ON(vcn < 0); | ||
150 | retry_remap: | ||
151 | /* Convert vcn to lcn. If that fails map the runlist and retry once. */ | ||
152 | lcn = ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn); | ||
153 | if (likely(lcn >= LCN_HOLE)) { | ||
154 | ntfs_debug("Done, lcn 0x%llx.", (long long)lcn); | ||
155 | return lcn; | ||
156 | } | ||
157 | if (lcn != LCN_RL_NOT_MAPPED) { | ||
158 | if (lcn != LCN_ENOENT) | ||
159 | lcn = LCN_EIO; | ||
160 | } else if (!is_retry) { | ||
161 | int err; | ||
162 | |||
163 | if (!write_locked) { | ||
164 | up_read(&ni->runlist.lock); | ||
165 | down_write(&ni->runlist.lock); | ||
166 | if (unlikely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) != | ||
167 | LCN_RL_NOT_MAPPED)) { | ||
168 | up_write(&ni->runlist.lock); | ||
169 | down_read(&ni->runlist.lock); | ||
170 | goto retry_remap; | ||
171 | } | ||
172 | } | ||
173 | err = ntfs_map_runlist_nolock(ni, vcn); | ||
174 | if (!write_locked) { | ||
175 | up_write(&ni->runlist.lock); | ||
176 | down_read(&ni->runlist.lock); | ||
177 | } | ||
178 | if (likely(!err)) { | ||
179 | is_retry = TRUE; | ||
180 | goto retry_remap; | ||
181 | } | ||
182 | if (err == -ENOENT) | ||
183 | lcn = LCN_ENOENT; | ||
184 | else if (err == -ENOMEM) | ||
185 | lcn = LCN_ENOMEM; | ||
186 | else | ||
187 | lcn = LCN_EIO; | ||
188 | } | ||
189 | if (lcn != LCN_ENOENT) | ||
190 | ntfs_error(ni->vol->sb, "Failed with error code %lli.", | ||
191 | (long long)lcn); | ||
192 | return lcn; | ||
193 | } | ||
194 | |||
195 | /** | ||
109 | * ntfs_find_vcn_nolock - find a vcn in the runlist described by an ntfs inode | 196 | * ntfs_find_vcn_nolock - find a vcn in the runlist described by an ntfs inode |
110 | * @ni: ntfs inode describing the runlist to search | 197 | * @ni: ntfs inode describing the runlist to search |
111 | * @vcn: vcn to find | 198 | * @vcn: vcn to find |
diff --git a/fs/ntfs/attrib.h b/fs/ntfs/attrib.h index 3eb451657025..75041c89c738 100644 --- a/fs/ntfs/attrib.h +++ b/fs/ntfs/attrib.h | |||
@@ -2,7 +2,7 @@ | |||
2 | * attrib.h - Defines for attribute handling in NTFS Linux kernel driver. | 2 | * attrib.h - Defines for attribute handling in NTFS Linux kernel driver. |
3 | * Part of the Linux-NTFS project. | 3 | * Part of the Linux-NTFS project. |
4 | * | 4 | * |
5 | * Copyright (c) 2001-2004 Anton Altaparmakov | 5 | * Copyright (c) 2001-2005 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 |
@@ -63,6 +63,9 @@ typedef struct { | |||
63 | extern int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn); | 63 | extern int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn); |
64 | extern int ntfs_map_runlist(ntfs_inode *ni, VCN vcn); | 64 | extern int ntfs_map_runlist(ntfs_inode *ni, VCN vcn); |
65 | 65 | ||
66 | extern LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, | ||
67 | const BOOL write_locked); | ||
68 | |||
66 | extern runlist_element *ntfs_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, | 69 | extern runlist_element *ntfs_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, |
67 | const BOOL write_locked); | 70 | const BOOL write_locked); |
68 | 71 | ||