aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ntfs/attrib.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ntfs/attrib.c')
-rw-r--r--fs/ntfs/attrib.c107
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 */
44int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) 44int 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
87put_err_out:
88 ntfs_attr_put_search_ctx(ctx); 76 ntfs_attr_put_search_ctx(ctx);
89err_out: 77err_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 */
95int 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 */
127runlist_element *ntfs_find_vcn(ntfs_inode *ni, const VCN vcn, 143runlist_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);
140lock_retry_remap: 156retry_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