diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-05-15 13:48:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-05-15 13:48:36 -0400 |
commit | 21b9f1c7e319f654de3b2574fe8d4e4114c9143f (patch) | |
tree | 7017dda7a6a811a59504f39d58eb65cbbbaffacd /fs | |
parent | eeba2dfa6a0d1cf40056e3a00ec21206c640eeca (diff) | |
parent | 4776cab43fd3111618112737a257dc3ef368eddd (diff) |
Merge tag 'afs-fixes-20180514' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs
Pull AFS fixes from David Howells:
"Here's a set of patches that fix a number of bugs in the in-kernel AFS
client, including:
- Fix directory locking to not use individual page locks for
directory reading/scanning but rather to use a semaphore on the
afs_vnode struct as the directory contents must be read in a single
blob and data from different reads must not be mixed as the entire
contents may be shuffled about between reads.
- Fix address list parsing to handle port specifiers correctly.
- Only give up callback records on a server if we actually talked to
that server (we might not be able to access a server).
- Fix some callback handling bugs, including refcounting,
whole-volume callbacks and when callbacks actually get broken in
response to a CB.CallBack op.
- Fix some server/address rotation bugs, including giving up if we
can't probe a server; giving up if a server says it doesn't have a
volume, but there are more servers to try.
- Fix the decoding of fetched statuses to be OpenAFS compatible.
- Fix the handling of server lookups in Cache Manager ops (such as
CB.InitCallBackState3) to use a UUID if possible and to handle no
server being found.
- Fix a bug in server lookup where not all addresses are compared.
- Fix the non-encryption of calls that prevents some servers from
being accessed (this also requires an AF_RXRPC patch that has
already gone in through the net tree).
There's also a patch that adds tracepoints to log Cache Manager ops
that don't find a matching server, either by UUID or by address"
* tag 'afs-fixes-20180514' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
afs: Fix the non-encryption of calls
afs: Fix CB.CallBack handling
afs: Fix whole-volume callback handling
afs: Fix afs_find_server search loop
afs: Fix the handling of an unfound server in CM operations
afs: Add a tracepoint to record callbacks from unlisted servers
afs: Fix the handling of CB.InitCallBackState3 to find the server by UUID
afs: Fix VNOVOL handling in address rotation
afs: Fix AFSFetchStatus decoder to provide OpenAFS compatibility
afs: Fix server rotation's handling of fileserver probe failure
afs: Fix refcounting in callback registration
afs: Fix giving up callbacks on server destruction
afs: Fix address list parsing
afs: Fix directory page locking
Diffstat (limited to 'fs')
-rw-r--r-- | fs/afs/addr_list.c | 25 | ||||
-rw-r--r-- | fs/afs/callback.c | 84 | ||||
-rw-r--r-- | fs/afs/cmservice.c | 67 | ||||
-rw-r--r-- | fs/afs/dir.c | 54 | ||||
-rw-r--r-- | fs/afs/file.c | 2 | ||||
-rw-r--r-- | fs/afs/flock.c | 6 | ||||
-rw-r--r-- | fs/afs/fsclient.c | 31 | ||||
-rw-r--r-- | fs/afs/inode.c | 19 | ||||
-rw-r--r-- | fs/afs/internal.h | 25 | ||||
-rw-r--r-- | fs/afs/rotate.c | 20 | ||||
-rw-r--r-- | fs/afs/rxrpc.c | 18 | ||||
-rw-r--r-- | fs/afs/security.c | 7 | ||||
-rw-r--r-- | fs/afs/server.c | 21 | ||||
-rw-r--r-- | fs/afs/server_list.c | 7 | ||||
-rw-r--r-- | fs/afs/super.c | 4 | ||||
-rw-r--r-- | fs/afs/write.c | 2 |
16 files changed, 224 insertions, 168 deletions
diff --git a/fs/afs/addr_list.c b/fs/afs/addr_list.c index 3bedfed608a2..7587fb665ff1 100644 --- a/fs/afs/addr_list.c +++ b/fs/afs/addr_list.c | |||
@@ -121,7 +121,7 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len, | |||
121 | p = text; | 121 | p = text; |
122 | do { | 122 | do { |
123 | struct sockaddr_rxrpc *srx = &alist->addrs[alist->nr_addrs]; | 123 | struct sockaddr_rxrpc *srx = &alist->addrs[alist->nr_addrs]; |
124 | char tdelim = delim; | 124 | const char *q, *stop; |
125 | 125 | ||
126 | if (*p == delim) { | 126 | if (*p == delim) { |
127 | p++; | 127 | p++; |
@@ -130,28 +130,33 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len, | |||
130 | 130 | ||
131 | if (*p == '[') { | 131 | if (*p == '[') { |
132 | p++; | 132 | p++; |
133 | tdelim = ']'; | 133 | q = memchr(p, ']', end - p); |
134 | } else { | ||
135 | for (q = p; q < end; q++) | ||
136 | if (*q == '+' || *q == delim) | ||
137 | break; | ||
134 | } | 138 | } |
135 | 139 | ||
136 | if (in4_pton(p, end - p, | 140 | if (in4_pton(p, q - p, |
137 | (u8 *)&srx->transport.sin6.sin6_addr.s6_addr32[3], | 141 | (u8 *)&srx->transport.sin6.sin6_addr.s6_addr32[3], |
138 | tdelim, &p)) { | 142 | -1, &stop)) { |
139 | srx->transport.sin6.sin6_addr.s6_addr32[0] = 0; | 143 | srx->transport.sin6.sin6_addr.s6_addr32[0] = 0; |
140 | srx->transport.sin6.sin6_addr.s6_addr32[1] = 0; | 144 | srx->transport.sin6.sin6_addr.s6_addr32[1] = 0; |
141 | srx->transport.sin6.sin6_addr.s6_addr32[2] = htonl(0xffff); | 145 | srx->transport.sin6.sin6_addr.s6_addr32[2] = htonl(0xffff); |
142 | } else if (in6_pton(p, end - p, | 146 | } else if (in6_pton(p, q - p, |
143 | srx->transport.sin6.sin6_addr.s6_addr, | 147 | srx->transport.sin6.sin6_addr.s6_addr, |
144 | tdelim, &p)) { | 148 | -1, &stop)) { |
145 | /* Nothing to do */ | 149 | /* Nothing to do */ |
146 | } else { | 150 | } else { |
147 | goto bad_address; | 151 | goto bad_address; |
148 | } | 152 | } |
149 | 153 | ||
150 | if (tdelim == ']') { | 154 | if (stop != q) |
151 | if (p == end || *p != ']') | 155 | goto bad_address; |
152 | goto bad_address; | 156 | |
157 | p = q; | ||
158 | if (q < end && *q == ']') | ||
153 | p++; | 159 | p++; |
154 | } | ||
155 | 160 | ||
156 | if (p < end) { | 161 | if (p < end) { |
157 | if (*p == '+') { | 162 | if (*p == '+') { |
diff --git a/fs/afs/callback.c b/fs/afs/callback.c index abd9a84f4e88..571437dcb252 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c | |||
@@ -23,36 +23,55 @@ | |||
23 | /* | 23 | /* |
24 | * Set up an interest-in-callbacks record for a volume on a server and | 24 | * Set up an interest-in-callbacks record for a volume on a server and |
25 | * register it with the server. | 25 | * register it with the server. |
26 | * - Called with volume->server_sem held. | 26 | * - Called with vnode->io_lock held. |
27 | */ | 27 | */ |
28 | int afs_register_server_cb_interest(struct afs_vnode *vnode, | 28 | int afs_register_server_cb_interest(struct afs_vnode *vnode, |
29 | struct afs_server_entry *entry) | 29 | struct afs_server_list *slist, |
30 | unsigned int index) | ||
30 | { | 31 | { |
31 | struct afs_cb_interest *cbi = entry->cb_interest, *vcbi, *new, *x; | 32 | struct afs_server_entry *entry = &slist->servers[index]; |
33 | struct afs_cb_interest *cbi, *vcbi, *new, *old; | ||
32 | struct afs_server *server = entry->server; | 34 | struct afs_server *server = entry->server; |
33 | 35 | ||
34 | again: | 36 | again: |
37 | if (vnode->cb_interest && | ||
38 | likely(vnode->cb_interest == entry->cb_interest)) | ||
39 | return 0; | ||
40 | |||
41 | read_lock(&slist->lock); | ||
42 | cbi = afs_get_cb_interest(entry->cb_interest); | ||
43 | read_unlock(&slist->lock); | ||
44 | |||
35 | vcbi = vnode->cb_interest; | 45 | vcbi = vnode->cb_interest; |
36 | if (vcbi) { | 46 | if (vcbi) { |
37 | if (vcbi == cbi) | 47 | if (vcbi == cbi) { |
48 | afs_put_cb_interest(afs_v2net(vnode), cbi); | ||
38 | return 0; | 49 | return 0; |
50 | } | ||
39 | 51 | ||
52 | /* Use a new interest in the server list for the same server | ||
53 | * rather than an old one that's still attached to a vnode. | ||
54 | */ | ||
40 | if (cbi && vcbi->server == cbi->server) { | 55 | if (cbi && vcbi->server == cbi->server) { |
41 | write_seqlock(&vnode->cb_lock); | 56 | write_seqlock(&vnode->cb_lock); |
42 | vnode->cb_interest = afs_get_cb_interest(cbi); | 57 | old = vnode->cb_interest; |
58 | vnode->cb_interest = cbi; | ||
43 | write_sequnlock(&vnode->cb_lock); | 59 | write_sequnlock(&vnode->cb_lock); |
44 | afs_put_cb_interest(afs_v2net(vnode), cbi); | 60 | afs_put_cb_interest(afs_v2net(vnode), old); |
45 | return 0; | 61 | return 0; |
46 | } | 62 | } |
47 | 63 | ||
64 | /* Re-use the one attached to the vnode. */ | ||
48 | if (!cbi && vcbi->server == server) { | 65 | if (!cbi && vcbi->server == server) { |
49 | afs_get_cb_interest(vcbi); | 66 | write_lock(&slist->lock); |
50 | x = cmpxchg(&entry->cb_interest, cbi, vcbi); | 67 | if (entry->cb_interest) { |
51 | if (x != cbi) { | 68 | write_unlock(&slist->lock); |
52 | cbi = x; | 69 | afs_put_cb_interest(afs_v2net(vnode), cbi); |
53 | afs_put_cb_interest(afs_v2net(vnode), vcbi); | ||
54 | goto again; | 70 | goto again; |
55 | } | 71 | } |
72 | |||
73 | entry->cb_interest = cbi; | ||
74 | write_unlock(&slist->lock); | ||
56 | return 0; | 75 | return 0; |
57 | } | 76 | } |
58 | } | 77 | } |
@@ -72,13 +91,16 @@ again: | |||
72 | list_add_tail(&new->cb_link, &server->cb_interests); | 91 | list_add_tail(&new->cb_link, &server->cb_interests); |
73 | write_unlock(&server->cb_break_lock); | 92 | write_unlock(&server->cb_break_lock); |
74 | 93 | ||
75 | x = cmpxchg(&entry->cb_interest, cbi, new); | 94 | write_lock(&slist->lock); |
76 | if (x == cbi) { | 95 | if (!entry->cb_interest) { |
96 | entry->cb_interest = afs_get_cb_interest(new); | ||
77 | cbi = new; | 97 | cbi = new; |
98 | new = NULL; | ||
78 | } else { | 99 | } else { |
79 | cbi = x; | 100 | cbi = afs_get_cb_interest(entry->cb_interest); |
80 | afs_put_cb_interest(afs_v2net(vnode), new); | ||
81 | } | 101 | } |
102 | write_unlock(&slist->lock); | ||
103 | afs_put_cb_interest(afs_v2net(vnode), new); | ||
82 | } | 104 | } |
83 | 105 | ||
84 | ASSERT(cbi); | 106 | ASSERT(cbi); |
@@ -88,11 +110,14 @@ again: | |||
88 | */ | 110 | */ |
89 | write_seqlock(&vnode->cb_lock); | 111 | write_seqlock(&vnode->cb_lock); |
90 | 112 | ||
91 | vnode->cb_interest = afs_get_cb_interest(cbi); | 113 | old = vnode->cb_interest; |
114 | vnode->cb_interest = cbi; | ||
92 | vnode->cb_s_break = cbi->server->cb_s_break; | 115 | vnode->cb_s_break = cbi->server->cb_s_break; |
116 | vnode->cb_v_break = vnode->volume->cb_v_break; | ||
93 | clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); | 117 | clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); |
94 | 118 | ||
95 | write_sequnlock(&vnode->cb_lock); | 119 | write_sequnlock(&vnode->cb_lock); |
120 | afs_put_cb_interest(afs_v2net(vnode), old); | ||
96 | return 0; | 121 | return 0; |
97 | } | 122 | } |
98 | 123 | ||
@@ -171,13 +196,24 @@ static void afs_break_one_callback(struct afs_server *server, | |||
171 | if (cbi->vid != fid->vid) | 196 | if (cbi->vid != fid->vid) |
172 | continue; | 197 | continue; |
173 | 198 | ||
174 | data.volume = NULL; | 199 | if (fid->vnode == 0 && fid->unique == 0) { |
175 | data.fid = *fid; | 200 | /* The callback break applies to an entire volume. */ |
176 | inode = ilookup5_nowait(cbi->sb, fid->vnode, afs_iget5_test, &data); | 201 | struct afs_super_info *as = AFS_FS_S(cbi->sb); |
177 | if (inode) { | 202 | struct afs_volume *volume = as->volume; |
178 | vnode = AFS_FS_I(inode); | 203 | |
179 | afs_break_callback(vnode); | 204 | write_lock(&volume->cb_break_lock); |
180 | iput(inode); | 205 | volume->cb_v_break++; |
206 | write_unlock(&volume->cb_break_lock); | ||
207 | } else { | ||
208 | data.volume = NULL; | ||
209 | data.fid = *fid; | ||
210 | inode = ilookup5_nowait(cbi->sb, fid->vnode, | ||
211 | afs_iget5_test, &data); | ||
212 | if (inode) { | ||
213 | vnode = AFS_FS_I(inode); | ||
214 | afs_break_callback(vnode); | ||
215 | iput(inode); | ||
216 | } | ||
181 | } | 217 | } |
182 | } | 218 | } |
183 | 219 | ||
@@ -195,6 +231,8 @@ void afs_break_callbacks(struct afs_server *server, size_t count, | |||
195 | ASSERT(server != NULL); | 231 | ASSERT(server != NULL); |
196 | ASSERTCMP(count, <=, AFSCBMAX); | 232 | ASSERTCMP(count, <=, AFSCBMAX); |
197 | 233 | ||
234 | /* TODO: Sort the callback break list by volume ID */ | ||
235 | |||
198 | for (; count > 0; callbacks++, count--) { | 236 | for (; count > 0; callbacks++, count--) { |
199 | _debug("- Fid { vl=%08x n=%u u=%u } CB { v=%u x=%u t=%u }", | 237 | _debug("- Fid { vl=%08x n=%u u=%u } CB { v=%u x=%u t=%u }", |
200 | callbacks->fid.vid, | 238 | callbacks->fid.vid, |
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index 357de908df3a..c332c95a6940 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c | |||
@@ -133,21 +133,10 @@ bool afs_cm_incoming_call(struct afs_call *call) | |||
133 | } | 133 | } |
134 | 134 | ||
135 | /* | 135 | /* |
136 | * clean up a cache manager call | 136 | * Clean up a cache manager call. |
137 | */ | 137 | */ |
138 | static void afs_cm_destructor(struct afs_call *call) | 138 | static void afs_cm_destructor(struct afs_call *call) |
139 | { | 139 | { |
140 | _enter(""); | ||
141 | |||
142 | /* Break the callbacks here so that we do it after the final ACK is | ||
143 | * received. The step number here must match the final number in | ||
144 | * afs_deliver_cb_callback(). | ||
145 | */ | ||
146 | if (call->unmarshall == 5) { | ||
147 | ASSERT(call->cm_server && call->count && call->request); | ||
148 | afs_break_callbacks(call->cm_server, call->count, call->request); | ||
149 | } | ||
150 | |||
151 | kfree(call->buffer); | 140 | kfree(call->buffer); |
152 | call->buffer = NULL; | 141 | call->buffer = NULL; |
153 | } | 142 | } |
@@ -161,14 +150,14 @@ static void SRXAFSCB_CallBack(struct work_struct *work) | |||
161 | 150 | ||
162 | _enter(""); | 151 | _enter(""); |
163 | 152 | ||
164 | /* be sure to send the reply *before* attempting to spam the AFS server | 153 | /* We need to break the callbacks before sending the reply as the |
165 | * with FSFetchStatus requests on the vnodes with broken callbacks lest | 154 | * server holds up change visibility till it receives our reply so as |
166 | * the AFS server get into a vicious cycle of trying to break further | 155 | * to maintain cache coherency. |
167 | * callbacks because it hadn't received completion of the CBCallBack op | 156 | */ |
168 | * yet */ | 157 | if (call->cm_server) |
169 | afs_send_empty_reply(call); | 158 | afs_break_callbacks(call->cm_server, call->count, call->request); |
170 | 159 | ||
171 | afs_break_callbacks(call->cm_server, call->count, call->request); | 160 | afs_send_empty_reply(call); |
172 | afs_put_call(call); | 161 | afs_put_call(call); |
173 | _leave(""); | 162 | _leave(""); |
174 | } | 163 | } |
@@ -180,7 +169,6 @@ static int afs_deliver_cb_callback(struct afs_call *call) | |||
180 | { | 169 | { |
181 | struct afs_callback_break *cb; | 170 | struct afs_callback_break *cb; |
182 | struct sockaddr_rxrpc srx; | 171 | struct sockaddr_rxrpc srx; |
183 | struct afs_server *server; | ||
184 | __be32 *bp; | 172 | __be32 *bp; |
185 | int ret, loop; | 173 | int ret, loop; |
186 | 174 | ||
@@ -267,15 +255,6 @@ static int afs_deliver_cb_callback(struct afs_call *call) | |||
267 | 255 | ||
268 | call->offset = 0; | 256 | call->offset = 0; |
269 | call->unmarshall++; | 257 | call->unmarshall++; |
270 | |||
271 | /* Record that the message was unmarshalled successfully so | ||
272 | * that the call destructor can know do the callback breaking | ||
273 | * work, even if the final ACK isn't received. | ||
274 | * | ||
275 | * If the step number changes, then afs_cm_destructor() must be | ||
276 | * updated also. | ||
277 | */ | ||
278 | call->unmarshall++; | ||
279 | case 5: | 258 | case 5: |
280 | break; | 259 | break; |
281 | } | 260 | } |
@@ -286,10 +265,9 @@ static int afs_deliver_cb_callback(struct afs_call *call) | |||
286 | /* we'll need the file server record as that tells us which set of | 265 | /* we'll need the file server record as that tells us which set of |
287 | * vnodes to operate upon */ | 266 | * vnodes to operate upon */ |
288 | rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx); | 267 | rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx); |
289 | server = afs_find_server(call->net, &srx); | 268 | call->cm_server = afs_find_server(call->net, &srx); |
290 | if (!server) | 269 | if (!call->cm_server) |
291 | return -ENOTCONN; | 270 | trace_afs_cm_no_server(call, &srx); |
292 | call->cm_server = server; | ||
293 | 271 | ||
294 | return afs_queue_call_work(call); | 272 | return afs_queue_call_work(call); |
295 | } | 273 | } |
@@ -303,7 +281,8 @@ static void SRXAFSCB_InitCallBackState(struct work_struct *work) | |||
303 | 281 | ||
304 | _enter("{%p}", call->cm_server); | 282 | _enter("{%p}", call->cm_server); |
305 | 283 | ||
306 | afs_init_callback_state(call->cm_server); | 284 | if (call->cm_server) |
285 | afs_init_callback_state(call->cm_server); | ||
307 | afs_send_empty_reply(call); | 286 | afs_send_empty_reply(call); |
308 | afs_put_call(call); | 287 | afs_put_call(call); |
309 | _leave(""); | 288 | _leave(""); |
@@ -315,7 +294,6 @@ static void SRXAFSCB_InitCallBackState(struct work_struct *work) | |||
315 | static int afs_deliver_cb_init_call_back_state(struct afs_call *call) | 294 | static int afs_deliver_cb_init_call_back_state(struct afs_call *call) |
316 | { | 295 | { |
317 | struct sockaddr_rxrpc srx; | 296 | struct sockaddr_rxrpc srx; |
318 | struct afs_server *server; | ||
319 | int ret; | 297 | int ret; |
320 | 298 | ||
321 | _enter(""); | 299 | _enter(""); |
@@ -328,10 +306,9 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call) | |||
328 | 306 | ||
329 | /* we'll need the file server record as that tells us which set of | 307 | /* we'll need the file server record as that tells us which set of |
330 | * vnodes to operate upon */ | 308 | * vnodes to operate upon */ |
331 | server = afs_find_server(call->net, &srx); | 309 | call->cm_server = afs_find_server(call->net, &srx); |
332 | if (!server) | 310 | if (!call->cm_server) |
333 | return -ENOTCONN; | 311 | trace_afs_cm_no_server(call, &srx); |
334 | call->cm_server = server; | ||
335 | 312 | ||
336 | return afs_queue_call_work(call); | 313 | return afs_queue_call_work(call); |
337 | } | 314 | } |
@@ -341,8 +318,6 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call) | |||
341 | */ | 318 | */ |
342 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) | 319 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) |
343 | { | 320 | { |
344 | struct sockaddr_rxrpc srx; | ||
345 | struct afs_server *server; | ||
346 | struct afs_uuid *r; | 321 | struct afs_uuid *r; |
347 | unsigned loop; | 322 | unsigned loop; |
348 | __be32 *b; | 323 | __be32 *b; |
@@ -398,11 +373,11 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) | |||
398 | 373 | ||
399 | /* we'll need the file server record as that tells us which set of | 374 | /* we'll need the file server record as that tells us which set of |
400 | * vnodes to operate upon */ | 375 | * vnodes to operate upon */ |
401 | rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx); | 376 | rcu_read_lock(); |
402 | server = afs_find_server(call->net, &srx); | 377 | call->cm_server = afs_find_server_by_uuid(call->net, call->request); |
403 | if (!server) | 378 | rcu_read_unlock(); |
404 | return -ENOTCONN; | 379 | if (!call->cm_server) |
405 | call->cm_server = server; | 380 | trace_afs_cm_no_server_u(call, call->request); |
406 | 381 | ||
407 | return afs_queue_call_work(call); | 382 | return afs_queue_call_work(call); |
408 | } | 383 | } |
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 5889f70d4d27..7d623008157f 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -180,6 +180,7 @@ static int afs_dir_open(struct inode *inode, struct file *file) | |||
180 | * get reclaimed during the iteration. | 180 | * get reclaimed during the iteration. |
181 | */ | 181 | */ |
182 | static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) | 182 | static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) |
183 | __acquires(&dvnode->validate_lock) | ||
183 | { | 184 | { |
184 | struct afs_read *req; | 185 | struct afs_read *req; |
185 | loff_t i_size; | 186 | loff_t i_size; |
@@ -261,18 +262,21 @@ retry: | |||
261 | /* If we're going to reload, we need to lock all the pages to prevent | 262 | /* If we're going to reload, we need to lock all the pages to prevent |
262 | * races. | 263 | * races. |
263 | */ | 264 | */ |
264 | if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) { | 265 | ret = -ERESTARTSYS; |
265 | ret = -ERESTARTSYS; | 266 | if (down_read_killable(&dvnode->validate_lock) < 0) |
266 | for (i = 0; i < req->nr_pages; i++) | 267 | goto error; |
267 | if (lock_page_killable(req->pages[i]) < 0) | ||
268 | goto error_unlock; | ||
269 | 268 | ||
270 | if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) | 269 | if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) |
271 | goto success; | 270 | goto success; |
271 | |||
272 | up_read(&dvnode->validate_lock); | ||
273 | if (down_write_killable(&dvnode->validate_lock) < 0) | ||
274 | goto error; | ||
272 | 275 | ||
276 | if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) { | ||
273 | ret = afs_fetch_data(dvnode, key, req); | 277 | ret = afs_fetch_data(dvnode, key, req); |
274 | if (ret < 0) | 278 | if (ret < 0) |
275 | goto error_unlock_all; | 279 | goto error_unlock; |
276 | 280 | ||
277 | task_io_account_read(PAGE_SIZE * req->nr_pages); | 281 | task_io_account_read(PAGE_SIZE * req->nr_pages); |
278 | 282 | ||
@@ -284,33 +288,26 @@ retry: | |||
284 | for (i = 0; i < req->nr_pages; i++) | 288 | for (i = 0; i < req->nr_pages; i++) |
285 | if (!afs_dir_check_page(dvnode, req->pages[i], | 289 | if (!afs_dir_check_page(dvnode, req->pages[i], |
286 | req->actual_len)) | 290 | req->actual_len)) |
287 | goto error_unlock_all; | 291 | goto error_unlock; |
288 | 292 | ||
289 | // TODO: Trim excess pages | 293 | // TODO: Trim excess pages |
290 | 294 | ||
291 | set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags); | 295 | set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags); |
292 | } | 296 | } |
293 | 297 | ||
298 | downgrade_write(&dvnode->validate_lock); | ||
294 | success: | 299 | success: |
295 | i = req->nr_pages; | ||
296 | while (i > 0) | ||
297 | unlock_page(req->pages[--i]); | ||
298 | return req; | 300 | return req; |
299 | 301 | ||
300 | error_unlock_all: | ||
301 | i = req->nr_pages; | ||
302 | error_unlock: | 302 | error_unlock: |
303 | while (i > 0) | 303 | up_write(&dvnode->validate_lock); |
304 | unlock_page(req->pages[--i]); | ||
305 | error: | 304 | error: |
306 | afs_put_read(req); | 305 | afs_put_read(req); |
307 | _leave(" = %d", ret); | 306 | _leave(" = %d", ret); |
308 | return ERR_PTR(ret); | 307 | return ERR_PTR(ret); |
309 | 308 | ||
310 | content_has_grown: | 309 | content_has_grown: |
311 | i = req->nr_pages; | 310 | up_write(&dvnode->validate_lock); |
312 | while (i > 0) | ||
313 | unlock_page(req->pages[--i]); | ||
314 | afs_put_read(req); | 311 | afs_put_read(req); |
315 | goto retry; | 312 | goto retry; |
316 | } | 313 | } |
@@ -473,6 +470,7 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, | |||
473 | } | 470 | } |
474 | 471 | ||
475 | out: | 472 | out: |
473 | up_read(&dvnode->validate_lock); | ||
476 | afs_put_read(req); | 474 | afs_put_read(req); |
477 | _leave(" = %d", ret); | 475 | _leave(" = %d", ret); |
478 | return ret; | 476 | return ret; |
@@ -1143,7 +1141,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
1143 | ret = -ERESTARTSYS; | 1141 | ret = -ERESTARTSYS; |
1144 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | 1142 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { |
1145 | while (afs_select_fileserver(&fc)) { | 1143 | while (afs_select_fileserver(&fc)) { |
1146 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1144 | fc.cb_break = afs_calc_vnode_cb_break(dvnode); |
1147 | afs_fs_create(&fc, dentry->d_name.name, mode, data_version, | 1145 | afs_fs_create(&fc, dentry->d_name.name, mode, data_version, |
1148 | &newfid, &newstatus, &newcb); | 1146 | &newfid, &newstatus, &newcb); |
1149 | } | 1147 | } |
@@ -1213,7 +1211,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1213 | ret = -ERESTARTSYS; | 1211 | ret = -ERESTARTSYS; |
1214 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | 1212 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { |
1215 | while (afs_select_fileserver(&fc)) { | 1213 | while (afs_select_fileserver(&fc)) { |
1216 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1214 | fc.cb_break = afs_calc_vnode_cb_break(dvnode); |
1217 | afs_fs_remove(&fc, dentry->d_name.name, true, | 1215 | afs_fs_remove(&fc, dentry->d_name.name, true, |
1218 | data_version); | 1216 | data_version); |
1219 | } | 1217 | } |
@@ -1316,7 +1314,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) | |||
1316 | ret = -ERESTARTSYS; | 1314 | ret = -ERESTARTSYS; |
1317 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | 1315 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { |
1318 | while (afs_select_fileserver(&fc)) { | 1316 | while (afs_select_fileserver(&fc)) { |
1319 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1317 | fc.cb_break = afs_calc_vnode_cb_break(dvnode); |
1320 | afs_fs_remove(&fc, dentry->d_name.name, false, | 1318 | afs_fs_remove(&fc, dentry->d_name.name, false, |
1321 | data_version); | 1319 | data_version); |
1322 | } | 1320 | } |
@@ -1373,7 +1371,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, | |||
1373 | ret = -ERESTARTSYS; | 1371 | ret = -ERESTARTSYS; |
1374 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | 1372 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { |
1375 | while (afs_select_fileserver(&fc)) { | 1373 | while (afs_select_fileserver(&fc)) { |
1376 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1374 | fc.cb_break = afs_calc_vnode_cb_break(dvnode); |
1377 | afs_fs_create(&fc, dentry->d_name.name, mode, data_version, | 1375 | afs_fs_create(&fc, dentry->d_name.name, mode, data_version, |
1378 | &newfid, &newstatus, &newcb); | 1376 | &newfid, &newstatus, &newcb); |
1379 | } | 1377 | } |
@@ -1443,8 +1441,8 @@ static int afs_link(struct dentry *from, struct inode *dir, | |||
1443 | } | 1441 | } |
1444 | 1442 | ||
1445 | while (afs_select_fileserver(&fc)) { | 1443 | while (afs_select_fileserver(&fc)) { |
1446 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1444 | fc.cb_break = afs_calc_vnode_cb_break(dvnode); |
1447 | fc.cb_break_2 = vnode->cb_break + vnode->cb_s_break; | 1445 | fc.cb_break_2 = afs_calc_vnode_cb_break(vnode); |
1448 | afs_fs_link(&fc, vnode, dentry->d_name.name, data_version); | 1446 | afs_fs_link(&fc, vnode, dentry->d_name.name, data_version); |
1449 | } | 1447 | } |
1450 | 1448 | ||
@@ -1512,7 +1510,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, | |||
1512 | ret = -ERESTARTSYS; | 1510 | ret = -ERESTARTSYS; |
1513 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | 1511 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { |
1514 | while (afs_select_fileserver(&fc)) { | 1512 | while (afs_select_fileserver(&fc)) { |
1515 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1513 | fc.cb_break = afs_calc_vnode_cb_break(dvnode); |
1516 | afs_fs_symlink(&fc, dentry->d_name.name, | 1514 | afs_fs_symlink(&fc, dentry->d_name.name, |
1517 | content, data_version, | 1515 | content, data_version, |
1518 | &newfid, &newstatus); | 1516 | &newfid, &newstatus); |
@@ -1588,8 +1586,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1588 | } | 1586 | } |
1589 | } | 1587 | } |
1590 | while (afs_select_fileserver(&fc)) { | 1588 | while (afs_select_fileserver(&fc)) { |
1591 | fc.cb_break = orig_dvnode->cb_break + orig_dvnode->cb_s_break; | 1589 | fc.cb_break = afs_calc_vnode_cb_break(orig_dvnode); |
1592 | fc.cb_break_2 = new_dvnode->cb_break + new_dvnode->cb_s_break; | 1590 | fc.cb_break_2 = afs_calc_vnode_cb_break(new_dvnode); |
1593 | afs_fs_rename(&fc, old_dentry->d_name.name, | 1591 | afs_fs_rename(&fc, old_dentry->d_name.name, |
1594 | new_dvnode, new_dentry->d_name.name, | 1592 | new_dvnode, new_dentry->d_name.name, |
1595 | orig_data_version, new_data_version); | 1593 | orig_data_version, new_data_version); |
diff --git a/fs/afs/file.c b/fs/afs/file.c index c24c08016dd9..7d4f26198573 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c | |||
@@ -238,7 +238,7 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *de | |||
238 | ret = -ERESTARTSYS; | 238 | ret = -ERESTARTSYS; |
239 | if (afs_begin_vnode_operation(&fc, vnode, key)) { | 239 | if (afs_begin_vnode_operation(&fc, vnode, key)) { |
240 | while (afs_select_fileserver(&fc)) { | 240 | while (afs_select_fileserver(&fc)) { |
241 | fc.cb_break = vnode->cb_break + vnode->cb_s_break; | 241 | fc.cb_break = afs_calc_vnode_cb_break(vnode); |
242 | afs_fs_fetch_data(&fc, desc); | 242 | afs_fs_fetch_data(&fc, desc); |
243 | } | 243 | } |
244 | 244 | ||
diff --git a/fs/afs/flock.c b/fs/afs/flock.c index 7a0e017070ec..dc62d15a964b 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c | |||
@@ -86,7 +86,7 @@ static int afs_set_lock(struct afs_vnode *vnode, struct key *key, | |||
86 | ret = -ERESTARTSYS; | 86 | ret = -ERESTARTSYS; |
87 | if (afs_begin_vnode_operation(&fc, vnode, key)) { | 87 | if (afs_begin_vnode_operation(&fc, vnode, key)) { |
88 | while (afs_select_fileserver(&fc)) { | 88 | while (afs_select_fileserver(&fc)) { |
89 | fc.cb_break = vnode->cb_break + vnode->cb_s_break; | 89 | fc.cb_break = afs_calc_vnode_cb_break(vnode); |
90 | afs_fs_set_lock(&fc, type); | 90 | afs_fs_set_lock(&fc, type); |
91 | } | 91 | } |
92 | 92 | ||
@@ -117,7 +117,7 @@ static int afs_extend_lock(struct afs_vnode *vnode, struct key *key) | |||
117 | ret = -ERESTARTSYS; | 117 | ret = -ERESTARTSYS; |
118 | if (afs_begin_vnode_operation(&fc, vnode, key)) { | 118 | if (afs_begin_vnode_operation(&fc, vnode, key)) { |
119 | while (afs_select_current_fileserver(&fc)) { | 119 | while (afs_select_current_fileserver(&fc)) { |
120 | fc.cb_break = vnode->cb_break + vnode->cb_s_break; | 120 | fc.cb_break = afs_calc_vnode_cb_break(vnode); |
121 | afs_fs_extend_lock(&fc); | 121 | afs_fs_extend_lock(&fc); |
122 | } | 122 | } |
123 | 123 | ||
@@ -148,7 +148,7 @@ static int afs_release_lock(struct afs_vnode *vnode, struct key *key) | |||
148 | ret = -ERESTARTSYS; | 148 | ret = -ERESTARTSYS; |
149 | if (afs_begin_vnode_operation(&fc, vnode, key)) { | 149 | if (afs_begin_vnode_operation(&fc, vnode, key)) { |
150 | while (afs_select_current_fileserver(&fc)) { | 150 | while (afs_select_current_fileserver(&fc)) { |
151 | fc.cb_break = vnode->cb_break + vnode->cb_s_break; | 151 | fc.cb_break = afs_calc_vnode_cb_break(vnode); |
152 | afs_fs_release_lock(&fc); | 152 | afs_fs_release_lock(&fc); |
153 | } | 153 | } |
154 | 154 | ||
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index efacdb7c1dee..b273e1d60478 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c | |||
@@ -134,6 +134,7 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call, | |||
134 | struct afs_read *read_req) | 134 | struct afs_read *read_req) |
135 | { | 135 | { |
136 | const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp; | 136 | const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp; |
137 | bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus); | ||
137 | u64 data_version, size; | 138 | u64 data_version, size; |
138 | u32 type, abort_code; | 139 | u32 type, abort_code; |
139 | u8 flags = 0; | 140 | u8 flags = 0; |
@@ -142,13 +143,32 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call, | |||
142 | if (vnode) | 143 | if (vnode) |
143 | write_seqlock(&vnode->cb_lock); | 144 | write_seqlock(&vnode->cb_lock); |
144 | 145 | ||
146 | abort_code = ntohl(xdr->abort_code); | ||
147 | |||
145 | if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) { | 148 | if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) { |
149 | if (xdr->if_version == htonl(0) && | ||
150 | abort_code != 0 && | ||
151 | inline_error) { | ||
152 | /* The OpenAFS fileserver has a bug in FS.InlineBulkStatus | ||
153 | * whereby it doesn't set the interface version in the error | ||
154 | * case. | ||
155 | */ | ||
156 | status->abort_code = abort_code; | ||
157 | ret = 0; | ||
158 | goto out; | ||
159 | } | ||
160 | |||
146 | pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version)); | 161 | pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version)); |
147 | goto bad; | 162 | goto bad; |
148 | } | 163 | } |
149 | 164 | ||
165 | if (abort_code != 0 && inline_error) { | ||
166 | status->abort_code = abort_code; | ||
167 | ret = 0; | ||
168 | goto out; | ||
169 | } | ||
170 | |||
150 | type = ntohl(xdr->type); | 171 | type = ntohl(xdr->type); |
151 | abort_code = ntohl(xdr->abort_code); | ||
152 | switch (type) { | 172 | switch (type) { |
153 | case AFS_FTYPE_FILE: | 173 | case AFS_FTYPE_FILE: |
154 | case AFS_FTYPE_DIR: | 174 | case AFS_FTYPE_DIR: |
@@ -165,13 +185,6 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call, | |||
165 | } | 185 | } |
166 | status->type = type; | 186 | status->type = type; |
167 | break; | 187 | break; |
168 | case AFS_FTYPE_INVALID: | ||
169 | if (abort_code != 0) { | ||
170 | status->abort_code = abort_code; | ||
171 | ret = 0; | ||
172 | goto out; | ||
173 | } | ||
174 | /* Fall through */ | ||
175 | default: | 188 | default: |
176 | goto bad; | 189 | goto bad; |
177 | } | 190 | } |
@@ -248,7 +261,7 @@ static void xdr_decode_AFSCallBack(struct afs_call *call, | |||
248 | 261 | ||
249 | write_seqlock(&vnode->cb_lock); | 262 | write_seqlock(&vnode->cb_lock); |
250 | 263 | ||
251 | if (call->cb_break == (vnode->cb_break + cbi->server->cb_s_break)) { | 264 | if (call->cb_break == afs_cb_break_sum(vnode, cbi)) { |
252 | vnode->cb_version = ntohl(*bp++); | 265 | vnode->cb_version = ntohl(*bp++); |
253 | cb_expiry = ntohl(*bp++); | 266 | cb_expiry = ntohl(*bp++); |
254 | vnode->cb_type = ntohl(*bp++); | 267 | vnode->cb_type = ntohl(*bp++); |
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 06194cfe9724..479b7fdda124 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c | |||
@@ -108,7 +108,7 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode) | |||
108 | ret = -ERESTARTSYS; | 108 | ret = -ERESTARTSYS; |
109 | if (afs_begin_vnode_operation(&fc, vnode, key)) { | 109 | if (afs_begin_vnode_operation(&fc, vnode, key)) { |
110 | while (afs_select_fileserver(&fc)) { | 110 | while (afs_select_fileserver(&fc)) { |
111 | fc.cb_break = vnode->cb_break + vnode->cb_s_break; | 111 | fc.cb_break = afs_calc_vnode_cb_break(vnode); |
112 | afs_fs_fetch_file_status(&fc, NULL, new_inode); | 112 | afs_fs_fetch_file_status(&fc, NULL, new_inode); |
113 | } | 113 | } |
114 | 114 | ||
@@ -393,15 +393,18 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) | |||
393 | read_seqlock_excl(&vnode->cb_lock); | 393 | read_seqlock_excl(&vnode->cb_lock); |
394 | 394 | ||
395 | if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { | 395 | if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { |
396 | if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break) { | 396 | if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break || |
397 | vnode->cb_v_break != vnode->volume->cb_v_break) { | ||
397 | vnode->cb_s_break = vnode->cb_interest->server->cb_s_break; | 398 | vnode->cb_s_break = vnode->cb_interest->server->cb_s_break; |
399 | vnode->cb_v_break = vnode->volume->cb_v_break; | ||
400 | valid = false; | ||
398 | } else if (vnode->status.type == AFS_FTYPE_DIR && | 401 | } else if (vnode->status.type == AFS_FTYPE_DIR && |
399 | test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) && | 402 | test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) && |
400 | vnode->cb_expires_at - 10 > now) { | 403 | vnode->cb_expires_at - 10 > now) { |
401 | valid = true; | 404 | valid = true; |
402 | } else if (!test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) && | 405 | } else if (!test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) && |
403 | vnode->cb_expires_at - 10 > now) { | 406 | vnode->cb_expires_at - 10 > now) { |
404 | valid = true; | 407 | valid = true; |
405 | } | 408 | } |
406 | } else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { | 409 | } else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { |
407 | valid = true; | 410 | valid = true; |
@@ -415,7 +418,7 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) | |||
415 | if (valid) | 418 | if (valid) |
416 | goto valid; | 419 | goto valid; |
417 | 420 | ||
418 | mutex_lock(&vnode->validate_lock); | 421 | down_write(&vnode->validate_lock); |
419 | 422 | ||
420 | /* if the promise has expired, we need to check the server again to get | 423 | /* if the promise has expired, we need to check the server again to get |
421 | * a new promise - note that if the (parent) directory's metadata was | 424 | * a new promise - note that if the (parent) directory's metadata was |
@@ -444,13 +447,13 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) | |||
444 | * different */ | 447 | * different */ |
445 | if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) | 448 | if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) |
446 | afs_zap_data(vnode); | 449 | afs_zap_data(vnode); |
447 | mutex_unlock(&vnode->validate_lock); | 450 | up_write(&vnode->validate_lock); |
448 | valid: | 451 | valid: |
449 | _leave(" = 0"); | 452 | _leave(" = 0"); |
450 | return 0; | 453 | return 0; |
451 | 454 | ||
452 | error_unlock: | 455 | error_unlock: |
453 | mutex_unlock(&vnode->validate_lock); | 456 | up_write(&vnode->validate_lock); |
454 | _leave(" = %d", ret); | 457 | _leave(" = %d", ret); |
455 | return ret; | 458 | return ret; |
456 | } | 459 | } |
@@ -574,7 +577,7 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr) | |||
574 | ret = -ERESTARTSYS; | 577 | ret = -ERESTARTSYS; |
575 | if (afs_begin_vnode_operation(&fc, vnode, key)) { | 578 | if (afs_begin_vnode_operation(&fc, vnode, key)) { |
576 | while (afs_select_fileserver(&fc)) { | 579 | while (afs_select_fileserver(&fc)) { |
577 | fc.cb_break = vnode->cb_break + vnode->cb_s_break; | 580 | fc.cb_break = afs_calc_vnode_cb_break(vnode); |
578 | afs_fs_setattr(&fc, attr); | 581 | afs_fs_setattr(&fc, attr); |
579 | } | 582 | } |
580 | 583 | ||
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index f8086ec95e24..e3f8a46663db 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -396,6 +396,7 @@ struct afs_server { | |||
396 | #define AFS_SERVER_FL_PROBED 5 /* The fileserver has been probed */ | 396 | #define AFS_SERVER_FL_PROBED 5 /* The fileserver has been probed */ |
397 | #define AFS_SERVER_FL_PROBING 6 /* Fileserver is being probed */ | 397 | #define AFS_SERVER_FL_PROBING 6 /* Fileserver is being probed */ |
398 | #define AFS_SERVER_FL_NO_IBULK 7 /* Fileserver doesn't support FS.InlineBulkStatus */ | 398 | #define AFS_SERVER_FL_NO_IBULK 7 /* Fileserver doesn't support FS.InlineBulkStatus */ |
399 | #define AFS_SERVER_FL_MAY_HAVE_CB 8 /* May have callbacks on this fileserver */ | ||
399 | atomic_t usage; | 400 | atomic_t usage; |
400 | u32 addr_version; /* Address list version */ | 401 | u32 addr_version; /* Address list version */ |
401 | 402 | ||
@@ -433,6 +434,7 @@ struct afs_server_list { | |||
433 | unsigned short index; /* Server currently in use */ | 434 | unsigned short index; /* Server currently in use */ |
434 | unsigned short vnovol_mask; /* Servers to be skipped due to VNOVOL */ | 435 | unsigned short vnovol_mask; /* Servers to be skipped due to VNOVOL */ |
435 | unsigned int seq; /* Set to ->servers_seq when installed */ | 436 | unsigned int seq; /* Set to ->servers_seq when installed */ |
437 | rwlock_t lock; | ||
436 | struct afs_server_entry servers[]; | 438 | struct afs_server_entry servers[]; |
437 | }; | 439 | }; |
438 | 440 | ||
@@ -459,6 +461,9 @@ struct afs_volume { | |||
459 | rwlock_t servers_lock; /* Lock for ->servers */ | 461 | rwlock_t servers_lock; /* Lock for ->servers */ |
460 | unsigned int servers_seq; /* Incremented each time ->servers changes */ | 462 | unsigned int servers_seq; /* Incremented each time ->servers changes */ |
461 | 463 | ||
464 | unsigned cb_v_break; /* Break-everything counter. */ | ||
465 | rwlock_t cb_break_lock; | ||
466 | |||
462 | afs_voltype_t type; /* type of volume */ | 467 | afs_voltype_t type; /* type of volume */ |
463 | short error; | 468 | short error; |
464 | char type_force; /* force volume type (suppress R/O -> R/W) */ | 469 | char type_force; /* force volume type (suppress R/O -> R/W) */ |
@@ -494,7 +499,7 @@ struct afs_vnode { | |||
494 | #endif | 499 | #endif |
495 | struct afs_permits __rcu *permit_cache; /* cache of permits so far obtained */ | 500 | struct afs_permits __rcu *permit_cache; /* cache of permits so far obtained */ |
496 | struct mutex io_lock; /* Lock for serialising I/O on this mutex */ | 501 | struct mutex io_lock; /* Lock for serialising I/O on this mutex */ |
497 | struct mutex validate_lock; /* lock for validating this vnode */ | 502 | struct rw_semaphore validate_lock; /* lock for validating this vnode */ |
498 | spinlock_t wb_lock; /* lock for wb_keys */ | 503 | spinlock_t wb_lock; /* lock for wb_keys */ |
499 | spinlock_t lock; /* waitqueue/flags lock */ | 504 | spinlock_t lock; /* waitqueue/flags lock */ |
500 | unsigned long flags; | 505 | unsigned long flags; |
@@ -519,6 +524,7 @@ struct afs_vnode { | |||
519 | /* outstanding callback notification on this file */ | 524 | /* outstanding callback notification on this file */ |
520 | struct afs_cb_interest *cb_interest; /* Server on which this resides */ | 525 | struct afs_cb_interest *cb_interest; /* Server on which this resides */ |
521 | unsigned int cb_s_break; /* Mass break counter on ->server */ | 526 | unsigned int cb_s_break; /* Mass break counter on ->server */ |
527 | unsigned int cb_v_break; /* Mass break counter on ->volume */ | ||
522 | unsigned int cb_break; /* Break counter on vnode */ | 528 | unsigned int cb_break; /* Break counter on vnode */ |
523 | seqlock_t cb_lock; /* Lock for ->cb_interest, ->status, ->cb_*break */ | 529 | seqlock_t cb_lock; /* Lock for ->cb_interest, ->status, ->cb_*break */ |
524 | 530 | ||
@@ -648,16 +654,29 @@ extern void afs_init_callback_state(struct afs_server *); | |||
648 | extern void afs_break_callback(struct afs_vnode *); | 654 | extern void afs_break_callback(struct afs_vnode *); |
649 | extern void afs_break_callbacks(struct afs_server *, size_t, struct afs_callback_break*); | 655 | extern void afs_break_callbacks(struct afs_server *, size_t, struct afs_callback_break*); |
650 | 656 | ||
651 | extern int afs_register_server_cb_interest(struct afs_vnode *, struct afs_server_entry *); | 657 | extern int afs_register_server_cb_interest(struct afs_vnode *, |
658 | struct afs_server_list *, unsigned int); | ||
652 | extern void afs_put_cb_interest(struct afs_net *, struct afs_cb_interest *); | 659 | extern void afs_put_cb_interest(struct afs_net *, struct afs_cb_interest *); |
653 | extern void afs_clear_callback_interests(struct afs_net *, struct afs_server_list *); | 660 | extern void afs_clear_callback_interests(struct afs_net *, struct afs_server_list *); |
654 | 661 | ||
655 | static inline struct afs_cb_interest *afs_get_cb_interest(struct afs_cb_interest *cbi) | 662 | static inline struct afs_cb_interest *afs_get_cb_interest(struct afs_cb_interest *cbi) |
656 | { | 663 | { |
657 | refcount_inc(&cbi->usage); | 664 | if (cbi) |
665 | refcount_inc(&cbi->usage); | ||
658 | return cbi; | 666 | return cbi; |
659 | } | 667 | } |
660 | 668 | ||
669 | static inline unsigned int afs_calc_vnode_cb_break(struct afs_vnode *vnode) | ||
670 | { | ||
671 | return vnode->cb_break + vnode->cb_s_break + vnode->cb_v_break; | ||
672 | } | ||
673 | |||
674 | static inline unsigned int afs_cb_break_sum(struct afs_vnode *vnode, | ||
675 | struct afs_cb_interest *cbi) | ||
676 | { | ||
677 | return vnode->cb_break + cbi->server->cb_s_break + vnode->volume->cb_v_break; | ||
678 | } | ||
679 | |||
661 | /* | 680 | /* |
662 | * cell.c | 681 | * cell.c |
663 | */ | 682 | */ |
diff --git a/fs/afs/rotate.c b/fs/afs/rotate.c index ac0feac9d746..e065bc0768e6 100644 --- a/fs/afs/rotate.c +++ b/fs/afs/rotate.c | |||
@@ -179,7 +179,7 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc) | |||
179 | */ | 179 | */ |
180 | if (fc->flags & AFS_FS_CURSOR_VNOVOL) { | 180 | if (fc->flags & AFS_FS_CURSOR_VNOVOL) { |
181 | fc->ac.error = -EREMOTEIO; | 181 | fc->ac.error = -EREMOTEIO; |
182 | goto failed; | 182 | goto next_server; |
183 | } | 183 | } |
184 | 184 | ||
185 | write_lock(&vnode->volume->servers_lock); | 185 | write_lock(&vnode->volume->servers_lock); |
@@ -201,7 +201,7 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc) | |||
201 | */ | 201 | */ |
202 | if (vnode->volume->servers == fc->server_list) { | 202 | if (vnode->volume->servers == fc->server_list) { |
203 | fc->ac.error = -EREMOTEIO; | 203 | fc->ac.error = -EREMOTEIO; |
204 | goto failed; | 204 | goto next_server; |
205 | } | 205 | } |
206 | 206 | ||
207 | /* Try again */ | 207 | /* Try again */ |
@@ -350,8 +350,8 @@ use_server: | |||
350 | * break request before we've finished decoding the reply and | 350 | * break request before we've finished decoding the reply and |
351 | * installing the vnode. | 351 | * installing the vnode. |
352 | */ | 352 | */ |
353 | fc->ac.error = afs_register_server_cb_interest( | 353 | fc->ac.error = afs_register_server_cb_interest(vnode, fc->server_list, |
354 | vnode, &fc->server_list->servers[fc->index]); | 354 | fc->index); |
355 | if (fc->ac.error < 0) | 355 | if (fc->ac.error < 0) |
356 | goto failed; | 356 | goto failed; |
357 | 357 | ||
@@ -369,8 +369,16 @@ use_server: | |||
369 | if (!test_bit(AFS_SERVER_FL_PROBED, &server->flags)) { | 369 | if (!test_bit(AFS_SERVER_FL_PROBED, &server->flags)) { |
370 | fc->ac.alist = afs_get_addrlist(alist); | 370 | fc->ac.alist = afs_get_addrlist(alist); |
371 | 371 | ||
372 | if (!afs_probe_fileserver(fc)) | 372 | if (!afs_probe_fileserver(fc)) { |
373 | goto failed; | 373 | switch (fc->ac.error) { |
374 | case -ENOMEM: | ||
375 | case -ERESTARTSYS: | ||
376 | case -EINTR: | ||
377 | goto failed; | ||
378 | default: | ||
379 | goto next_server; | ||
380 | } | ||
381 | } | ||
374 | } | 382 | } |
375 | 383 | ||
376 | if (!fc->ac.alist) | 384 | if (!fc->ac.alist) |
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 5c6263972ec9..08735948f15d 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c | |||
@@ -41,6 +41,7 @@ int afs_open_socket(struct afs_net *net) | |||
41 | { | 41 | { |
42 | struct sockaddr_rxrpc srx; | 42 | struct sockaddr_rxrpc srx; |
43 | struct socket *socket; | 43 | struct socket *socket; |
44 | unsigned int min_level; | ||
44 | int ret; | 45 | int ret; |
45 | 46 | ||
46 | _enter(""); | 47 | _enter(""); |
@@ -60,6 +61,12 @@ int afs_open_socket(struct afs_net *net) | |||
60 | srx.transport.sin6.sin6_family = AF_INET6; | 61 | srx.transport.sin6.sin6_family = AF_INET6; |
61 | srx.transport.sin6.sin6_port = htons(AFS_CM_PORT); | 62 | srx.transport.sin6.sin6_port = htons(AFS_CM_PORT); |
62 | 63 | ||
64 | min_level = RXRPC_SECURITY_ENCRYPT; | ||
65 | ret = kernel_setsockopt(socket, SOL_RXRPC, RXRPC_MIN_SECURITY_LEVEL, | ||
66 | (void *)&min_level, sizeof(min_level)); | ||
67 | if (ret < 0) | ||
68 | goto error_2; | ||
69 | |||
63 | ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); | 70 | ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); |
64 | if (ret == -EADDRINUSE) { | 71 | if (ret == -EADDRINUSE) { |
65 | srx.transport.sin6.sin6_port = 0; | 72 | srx.transport.sin6.sin6_port = 0; |
@@ -482,8 +489,12 @@ static void afs_deliver_to_call(struct afs_call *call) | |||
482 | state = READ_ONCE(call->state); | 489 | state = READ_ONCE(call->state); |
483 | switch (ret) { | 490 | switch (ret) { |
484 | case 0: | 491 | case 0: |
485 | if (state == AFS_CALL_CL_PROC_REPLY) | 492 | if (state == AFS_CALL_CL_PROC_REPLY) { |
493 | if (call->cbi) | ||
494 | set_bit(AFS_SERVER_FL_MAY_HAVE_CB, | ||
495 | &call->cbi->server->flags); | ||
486 | goto call_complete; | 496 | goto call_complete; |
497 | } | ||
487 | ASSERTCMP(state, >, AFS_CALL_CL_PROC_REPLY); | 498 | ASSERTCMP(state, >, AFS_CALL_CL_PROC_REPLY); |
488 | goto done; | 499 | goto done; |
489 | case -EINPROGRESS: | 500 | case -EINPROGRESS: |
@@ -493,11 +504,6 @@ static void afs_deliver_to_call(struct afs_call *call) | |||
493 | case -ECONNABORTED: | 504 | case -ECONNABORTED: |
494 | ASSERTCMP(state, ==, AFS_CALL_COMPLETE); | 505 | ASSERTCMP(state, ==, AFS_CALL_COMPLETE); |
495 | goto done; | 506 | goto done; |
496 | case -ENOTCONN: | ||
497 | abort_code = RX_CALL_DEAD; | ||
498 | rxrpc_kernel_abort_call(call->net->socket, call->rxcall, | ||
499 | abort_code, ret, "KNC"); | ||
500 | goto local_abort; | ||
501 | case -ENOTSUPP: | 507 | case -ENOTSUPP: |
502 | abort_code = RXGEN_OPCODE; | 508 | abort_code = RXGEN_OPCODE; |
503 | rxrpc_kernel_abort_call(call->net->socket, call->rxcall, | 509 | rxrpc_kernel_abort_call(call->net->socket, call->rxcall, |
diff --git a/fs/afs/security.c b/fs/afs/security.c index cea2fff313dc..1992b0ffa543 100644 --- a/fs/afs/security.c +++ b/fs/afs/security.c | |||
@@ -147,8 +147,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key, | |||
147 | break; | 147 | break; |
148 | } | 148 | } |
149 | 149 | ||
150 | if (cb_break != (vnode->cb_break + | 150 | if (cb_break != afs_cb_break_sum(vnode, vnode->cb_interest)) { |
151 | vnode->cb_interest->server->cb_s_break)) { | ||
152 | changed = true; | 151 | changed = true; |
153 | break; | 152 | break; |
154 | } | 153 | } |
@@ -178,7 +177,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key, | |||
178 | } | 177 | } |
179 | } | 178 | } |
180 | 179 | ||
181 | if (cb_break != (vnode->cb_break + vnode->cb_interest->server->cb_s_break)) | 180 | if (cb_break != afs_cb_break_sum(vnode, vnode->cb_interest)) |
182 | goto someone_else_changed_it; | 181 | goto someone_else_changed_it; |
183 | 182 | ||
184 | /* We need a ref on any permits list we want to copy as we'll have to | 183 | /* We need a ref on any permits list we want to copy as we'll have to |
@@ -257,7 +256,7 @@ found: | |||
257 | 256 | ||
258 | spin_lock(&vnode->lock); | 257 | spin_lock(&vnode->lock); |
259 | zap = rcu_access_pointer(vnode->permit_cache); | 258 | zap = rcu_access_pointer(vnode->permit_cache); |
260 | if (cb_break == (vnode->cb_break + vnode->cb_interest->server->cb_s_break) && | 259 | if (cb_break == afs_cb_break_sum(vnode, vnode->cb_interest) && |
261 | zap == permits) | 260 | zap == permits) |
262 | rcu_assign_pointer(vnode->permit_cache, replacement); | 261 | rcu_assign_pointer(vnode->permit_cache, replacement); |
263 | else | 262 | else |
diff --git a/fs/afs/server.c b/fs/afs/server.c index 629c74986cff..3af4625e2f8c 100644 --- a/fs/afs/server.c +++ b/fs/afs/server.c | |||
@@ -67,12 +67,6 @@ struct afs_server *afs_find_server(struct afs_net *net, | |||
67 | sizeof(struct in6_addr)); | 67 | sizeof(struct in6_addr)); |
68 | if (diff == 0) | 68 | if (diff == 0) |
69 | goto found; | 69 | goto found; |
70 | if (diff < 0) { | ||
71 | // TODO: Sort the list | ||
72 | //if (i == alist->nr_ipv4) | ||
73 | // goto not_found; | ||
74 | break; | ||
75 | } | ||
76 | } | 70 | } |
77 | } | 71 | } |
78 | } else { | 72 | } else { |
@@ -87,17 +81,10 @@ struct afs_server *afs_find_server(struct afs_net *net, | |||
87 | (u32 __force)b->sin6_addr.s6_addr32[3]); | 81 | (u32 __force)b->sin6_addr.s6_addr32[3]); |
88 | if (diff == 0) | 82 | if (diff == 0) |
89 | goto found; | 83 | goto found; |
90 | if (diff < 0) { | ||
91 | // TODO: Sort the list | ||
92 | //if (i == 0) | ||
93 | // goto not_found; | ||
94 | break; | ||
95 | } | ||
96 | } | 84 | } |
97 | } | 85 | } |
98 | } | 86 | } |
99 | 87 | ||
100 | //not_found: | ||
101 | server = NULL; | 88 | server = NULL; |
102 | found: | 89 | found: |
103 | if (server && !atomic_inc_not_zero(&server->usage)) | 90 | if (server && !atomic_inc_not_zero(&server->usage)) |
@@ -395,14 +382,16 @@ static void afs_destroy_server(struct afs_net *net, struct afs_server *server) | |||
395 | struct afs_addr_list *alist = rcu_access_pointer(server->addresses); | 382 | struct afs_addr_list *alist = rcu_access_pointer(server->addresses); |
396 | struct afs_addr_cursor ac = { | 383 | struct afs_addr_cursor ac = { |
397 | .alist = alist, | 384 | .alist = alist, |
398 | .addr = &alist->addrs[0], | ||
399 | .start = alist->index, | 385 | .start = alist->index, |
400 | .index = alist->index, | 386 | .index = 0, |
387 | .addr = &alist->addrs[alist->index], | ||
401 | .error = 0, | 388 | .error = 0, |
402 | }; | 389 | }; |
403 | _enter("%p", server); | 390 | _enter("%p", server); |
404 | 391 | ||
405 | afs_fs_give_up_all_callbacks(net, server, &ac, NULL); | 392 | if (test_bit(AFS_SERVER_FL_MAY_HAVE_CB, &server->flags)) |
393 | afs_fs_give_up_all_callbacks(net, server, &ac, NULL); | ||
394 | |||
406 | call_rcu(&server->rcu, afs_server_rcu); | 395 | call_rcu(&server->rcu, afs_server_rcu); |
407 | afs_dec_servers_outstanding(net); | 396 | afs_dec_servers_outstanding(net); |
408 | } | 397 | } |
diff --git a/fs/afs/server_list.c b/fs/afs/server_list.c index 0f8dc4c8f07c..8a5760aa5832 100644 --- a/fs/afs/server_list.c +++ b/fs/afs/server_list.c | |||
@@ -49,6 +49,7 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell, | |||
49 | goto error; | 49 | goto error; |
50 | 50 | ||
51 | refcount_set(&slist->usage, 1); | 51 | refcount_set(&slist->usage, 1); |
52 | rwlock_init(&slist->lock); | ||
52 | 53 | ||
53 | /* Make sure a records exists for each server in the list. */ | 54 | /* Make sure a records exists for each server in the list. */ |
54 | for (i = 0; i < vldb->nr_servers; i++) { | 55 | for (i = 0; i < vldb->nr_servers; i++) { |
@@ -64,9 +65,11 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell, | |||
64 | goto error_2; | 65 | goto error_2; |
65 | } | 66 | } |
66 | 67 | ||
67 | /* Insertion-sort by server pointer */ | 68 | /* Insertion-sort by UUID */ |
68 | for (j = 0; j < slist->nr_servers; j++) | 69 | for (j = 0; j < slist->nr_servers; j++) |
69 | if (slist->servers[j].server >= server) | 70 | if (memcmp(&slist->servers[j].server->uuid, |
71 | &server->uuid, | ||
72 | sizeof(server->uuid)) >= 0) | ||
70 | break; | 73 | break; |
71 | if (j < slist->nr_servers) { | 74 | if (j < slist->nr_servers) { |
72 | if (slist->servers[j].server == server) { | 75 | if (slist->servers[j].server == server) { |
diff --git a/fs/afs/super.c b/fs/afs/super.c index 65081ec3c36e..9e5d7966621c 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
@@ -590,7 +590,7 @@ static void afs_i_init_once(void *_vnode) | |||
590 | memset(vnode, 0, sizeof(*vnode)); | 590 | memset(vnode, 0, sizeof(*vnode)); |
591 | inode_init_once(&vnode->vfs_inode); | 591 | inode_init_once(&vnode->vfs_inode); |
592 | mutex_init(&vnode->io_lock); | 592 | mutex_init(&vnode->io_lock); |
593 | mutex_init(&vnode->validate_lock); | 593 | init_rwsem(&vnode->validate_lock); |
594 | spin_lock_init(&vnode->wb_lock); | 594 | spin_lock_init(&vnode->wb_lock); |
595 | spin_lock_init(&vnode->lock); | 595 | spin_lock_init(&vnode->lock); |
596 | INIT_LIST_HEAD(&vnode->wb_keys); | 596 | INIT_LIST_HEAD(&vnode->wb_keys); |
@@ -688,7 +688,7 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
688 | if (afs_begin_vnode_operation(&fc, vnode, key)) { | 688 | if (afs_begin_vnode_operation(&fc, vnode, key)) { |
689 | fc.flags |= AFS_FS_CURSOR_NO_VSLEEP; | 689 | fc.flags |= AFS_FS_CURSOR_NO_VSLEEP; |
690 | while (afs_select_fileserver(&fc)) { | 690 | while (afs_select_fileserver(&fc)) { |
691 | fc.cb_break = vnode->cb_break + vnode->cb_s_break; | 691 | fc.cb_break = afs_calc_vnode_cb_break(vnode); |
692 | afs_fs_get_volume_status(&fc, &vs); | 692 | afs_fs_get_volume_status(&fc, &vs); |
693 | } | 693 | } |
694 | 694 | ||
diff --git a/fs/afs/write.c b/fs/afs/write.c index c164698dc304..8b39e6ebb40b 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c | |||
@@ -351,7 +351,7 @@ found_key: | |||
351 | ret = -ERESTARTSYS; | 351 | ret = -ERESTARTSYS; |
352 | if (afs_begin_vnode_operation(&fc, vnode, wbk->key)) { | 352 | if (afs_begin_vnode_operation(&fc, vnode, wbk->key)) { |
353 | while (afs_select_fileserver(&fc)) { | 353 | while (afs_select_fileserver(&fc)) { |
354 | fc.cb_break = vnode->cb_break + vnode->cb_s_break; | 354 | fc.cb_break = afs_calc_vnode_cb_break(vnode); |
355 | afs_fs_store_data(&fc, mapping, first, last, offset, to); | 355 | afs_fs_store_data(&fc, mapping, first, last, offset, to); |
356 | } | 356 | } |
357 | 357 | ||