diff options
author | David Howells <dhowells@redhat.com> | 2019-04-25 09:26:50 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2019-04-25 09:26:50 -0400 |
commit | 4be5975aea154e164696128d049dec9ed341585c (patch) | |
tree | c87c5444b7b41dac9016dcfabd6e4b1945759767 /fs/afs | |
parent | 68ce801ffd82e72d5005ab5458e8b9e59f24d9cc (diff) |
afs: Further fix file locking
Further fix the file locking in the afs filesystem client in a number of
ways, including:
(1) Don't submit the operation to obtain a lock from the server in a work
queue context, but rather do it in the process context of whoever
issued the requesting system call.
(2) The owner of the file_lock struct at the front of the pending_locks
queue now owns right to talk to the server.
(3) Write locks can be instantly granted if they don't overlap with any
other locks *and* we have a write lock on the server.
(4) In the event of an authentication/permission error, all other matching
pending locks requests are also immediately aborted.
(5) Properly use VFS core locks_lock_file_wait() to distribute the server
lock amongst local client locks, including waiting for the lock to
become available.
Test with:
sqlite3 /afs/.../scratch/billings.sqlite <<EOF
CREATE TABLE hosts (
hostname varchar(80),
shorthost varchar(80),
room varchar(30),
building varchar(30),
PRIMARY KEY(shorthost)
);
EOF
With the version of sqlite3 that I have, this should fail consistently with
EAGAIN, whether or not the program is straced (which introduces some delays
between lock syscalls).
Fixes: 0fafdc9f888b ("afs: Fix file locking")
Reported-by: Jonathan Billings <jsbillin@umich.edu>
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/afs')
-rw-r--r-- | fs/afs/flock.c | 390 |
1 files changed, 195 insertions, 195 deletions
diff --git a/fs/afs/flock.c b/fs/afs/flock.c index 6919f53ed4ad..827d5a711088 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c | |||
@@ -13,9 +13,11 @@ | |||
13 | 13 | ||
14 | #define AFS_LOCK_GRANTED 0 | 14 | #define AFS_LOCK_GRANTED 0 |
15 | #define AFS_LOCK_PENDING 1 | 15 | #define AFS_LOCK_PENDING 1 |
16 | #define AFS_LOCK_YOUR_TRY 2 | ||
16 | 17 | ||
17 | struct workqueue_struct *afs_lock_manager; | 18 | struct workqueue_struct *afs_lock_manager; |
18 | 19 | ||
20 | static void afs_next_locker(struct afs_vnode *vnode, int error); | ||
19 | static void afs_fl_copy_lock(struct file_lock *new, struct file_lock *fl); | 21 | static void afs_fl_copy_lock(struct file_lock *new, struct file_lock *fl); |
20 | static void afs_fl_release_private(struct file_lock *fl); | 22 | static void afs_fl_release_private(struct file_lock *fl); |
21 | 23 | ||
@@ -24,6 +26,12 @@ static const struct file_lock_operations afs_lock_ops = { | |||
24 | .fl_release_private = afs_fl_release_private, | 26 | .fl_release_private = afs_fl_release_private, |
25 | }; | 27 | }; |
26 | 28 | ||
29 | static inline void afs_set_lock_state(struct afs_vnode *vnode, enum afs_lock_state state) | ||
30 | { | ||
31 | _debug("STATE %u -> %u", vnode->lock_state, state); | ||
32 | vnode->lock_state = state; | ||
33 | } | ||
34 | |||
27 | /* | 35 | /* |
28 | * if the callback is broken on this vnode, then the lock may now be available | 36 | * if the callback is broken on this vnode, then the lock may now be available |
29 | */ | 37 | */ |
@@ -31,7 +39,13 @@ void afs_lock_may_be_available(struct afs_vnode *vnode) | |||
31 | { | 39 | { |
32 | _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode); | 40 | _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode); |
33 | 41 | ||
34 | queue_delayed_work(afs_lock_manager, &vnode->lock_work, 0); | 42 | if (vnode->lock_state != AFS_VNODE_LOCK_WAITING_FOR_CB) |
43 | return; | ||
44 | |||
45 | spin_lock(&vnode->lock); | ||
46 | if (vnode->lock_state == AFS_VNODE_LOCK_WAITING_FOR_CB) | ||
47 | afs_next_locker(vnode, 0); | ||
48 | spin_unlock(&vnode->lock); | ||
35 | } | 49 | } |
36 | 50 | ||
37 | /* | 51 | /* |
@@ -75,22 +89,65 @@ void afs_lock_op_done(struct afs_call *call) | |||
75 | * first lock in the queue is itself a readlock) | 89 | * first lock in the queue is itself a readlock) |
76 | * - the caller must hold the vnode lock | 90 | * - the caller must hold the vnode lock |
77 | */ | 91 | */ |
78 | static void afs_grant_locks(struct afs_vnode *vnode, struct file_lock *fl) | 92 | static void afs_grant_locks(struct afs_vnode *vnode) |
79 | { | 93 | { |
80 | struct file_lock *p, *_p; | 94 | struct file_lock *p, *_p; |
95 | bool exclusive = (vnode->lock_type == AFS_LOCK_WRITE); | ||
81 | 96 | ||
82 | list_move_tail(&fl->fl_u.afs.link, &vnode->granted_locks); | 97 | list_for_each_entry_safe(p, _p, &vnode->pending_locks, fl_u.afs.link) { |
83 | if (fl->fl_type == F_RDLCK) { | 98 | if (!exclusive && p->fl_type == F_WRLCK) |
84 | list_for_each_entry_safe(p, _p, &vnode->pending_locks, | 99 | continue; |
85 | fl_u.afs.link) { | 100 | |
86 | if (p->fl_type == F_RDLCK) { | 101 | list_move_tail(&p->fl_u.afs.link, &vnode->granted_locks); |
87 | p->fl_u.afs.state = AFS_LOCK_GRANTED; | 102 | p->fl_u.afs.state = AFS_LOCK_GRANTED; |
88 | list_move_tail(&p->fl_u.afs.link, | 103 | wake_up(&p->fl_wait); |
89 | &vnode->granted_locks); | 104 | } |
90 | wake_up(&p->fl_wait); | 105 | } |
91 | } | 106 | |
107 | /* | ||
108 | * If an error is specified, reject every pending lock that matches the | ||
109 | * authentication and type of the lock we failed to get. If there are any | ||
110 | * remaining lockers, try to wake up one of them to have a go. | ||
111 | */ | ||
112 | static void afs_next_locker(struct afs_vnode *vnode, int error) | ||
113 | { | ||
114 | struct file_lock *p, *_p, *next = NULL; | ||
115 | struct key *key = vnode->lock_key; | ||
116 | unsigned int fl_type = F_RDLCK; | ||
117 | |||
118 | _enter(""); | ||
119 | |||
120 | if (vnode->lock_type == AFS_LOCK_WRITE) | ||
121 | fl_type = F_WRLCK; | ||
122 | |||
123 | list_for_each_entry_safe(p, _p, &vnode->pending_locks, fl_u.afs.link) { | ||
124 | if (error && | ||
125 | p->fl_type == fl_type && | ||
126 | afs_file_key(p->fl_file) == key) { | ||
127 | list_del_init(&p->fl_u.afs.link); | ||
128 | p->fl_u.afs.state = error; | ||
129 | wake_up(&p->fl_wait); | ||
92 | } | 130 | } |
131 | |||
132 | /* Select the next locker to hand off to. */ | ||
133 | if (next && | ||
134 | (next->fl_type == F_WRLCK || p->fl_type == F_RDLCK)) | ||
135 | continue; | ||
136 | next = p; | ||
93 | } | 137 | } |
138 | |||
139 | vnode->lock_key = NULL; | ||
140 | key_put(key); | ||
141 | |||
142 | if (next) { | ||
143 | afs_set_lock_state(vnode, AFS_VNODE_LOCK_SETTING); | ||
144 | next->fl_u.afs.state = AFS_LOCK_YOUR_TRY; | ||
145 | wake_up(&next->fl_wait); | ||
146 | } else { | ||
147 | afs_set_lock_state(vnode, AFS_VNODE_LOCK_NONE); | ||
148 | } | ||
149 | |||
150 | _leave(""); | ||
94 | } | 151 | } |
95 | 152 | ||
96 | /* | 153 | /* |
@@ -196,8 +253,6 @@ void afs_lock_work(struct work_struct *work) | |||
196 | { | 253 | { |
197 | struct afs_vnode *vnode = | 254 | struct afs_vnode *vnode = |
198 | container_of(work, struct afs_vnode, lock_work.work); | 255 | container_of(work, struct afs_vnode, lock_work.work); |
199 | struct file_lock *fl, *next; | ||
200 | afs_lock_type_t type; | ||
201 | struct key *key; | 256 | struct key *key; |
202 | int ret; | 257 | int ret; |
203 | 258 | ||
@@ -210,7 +265,7 @@ again: | |||
210 | switch (vnode->lock_state) { | 265 | switch (vnode->lock_state) { |
211 | case AFS_VNODE_LOCK_NEED_UNLOCK: | 266 | case AFS_VNODE_LOCK_NEED_UNLOCK: |
212 | _debug("unlock"); | 267 | _debug("unlock"); |
213 | vnode->lock_state = AFS_VNODE_LOCK_UNLOCKING; | 268 | afs_set_lock_state(vnode, AFS_VNODE_LOCK_UNLOCKING); |
214 | spin_unlock(&vnode->lock); | 269 | spin_unlock(&vnode->lock); |
215 | 270 | ||
216 | /* attempt to release the server lock; if it fails, we just | 271 | /* attempt to release the server lock; if it fails, we just |
@@ -222,22 +277,9 @@ again: | |||
222 | vnode->fid.vid, vnode->fid.vnode, ret); | 277 | vnode->fid.vid, vnode->fid.vnode, ret); |
223 | 278 | ||
224 | spin_lock(&vnode->lock); | 279 | spin_lock(&vnode->lock); |
225 | key_put(vnode->lock_key); | 280 | afs_next_locker(vnode, 0); |
226 | vnode->lock_key = NULL; | 281 | spin_unlock(&vnode->lock); |
227 | vnode->lock_state = AFS_VNODE_LOCK_NONE; | 282 | return; |
228 | |||
229 | if (list_empty(&vnode->pending_locks)) { | ||
230 | spin_unlock(&vnode->lock); | ||
231 | return; | ||
232 | } | ||
233 | |||
234 | /* The new front of the queue now owns the state variables. */ | ||
235 | next = list_entry(vnode->pending_locks.next, | ||
236 | struct file_lock, fl_u.afs.link); | ||
237 | vnode->lock_key = key_get(afs_file_key(next->fl_file)); | ||
238 | vnode->lock_type = (next->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE; | ||
239 | vnode->lock_state = AFS_VNODE_LOCK_WAITING_FOR_CB; | ||
240 | goto again; | ||
241 | 283 | ||
242 | /* If we've already got a lock, then it must be time to extend that | 284 | /* If we've already got a lock, then it must be time to extend that |
243 | * lock as AFS locks time out after 5 minutes. | 285 | * lock as AFS locks time out after 5 minutes. |
@@ -248,7 +290,7 @@ again: | |||
248 | ASSERT(!list_empty(&vnode->granted_locks)); | 290 | ASSERT(!list_empty(&vnode->granted_locks)); |
249 | 291 | ||
250 | key = key_get(vnode->lock_key); | 292 | key = key_get(vnode->lock_key); |
251 | vnode->lock_state = AFS_VNODE_LOCK_EXTENDING; | 293 | afs_set_lock_state(vnode, AFS_VNODE_LOCK_EXTENDING); |
252 | spin_unlock(&vnode->lock); | 294 | spin_unlock(&vnode->lock); |
253 | 295 | ||
254 | ret = afs_extend_lock(vnode, key); /* RPC */ | 296 | ret = afs_extend_lock(vnode, key); /* RPC */ |
@@ -262,72 +304,26 @@ again: | |||
262 | 304 | ||
263 | if (vnode->lock_state != AFS_VNODE_LOCK_EXTENDING) | 305 | if (vnode->lock_state != AFS_VNODE_LOCK_EXTENDING) |
264 | goto again; | 306 | goto again; |
265 | vnode->lock_state = AFS_VNODE_LOCK_GRANTED; | 307 | afs_set_lock_state(vnode, AFS_VNODE_LOCK_GRANTED); |
266 | 308 | ||
267 | if (ret == 0) | 309 | if (ret != 0) |
268 | afs_schedule_lock_extension(vnode); | ||
269 | else | ||
270 | queue_delayed_work(afs_lock_manager, &vnode->lock_work, | 310 | queue_delayed_work(afs_lock_manager, &vnode->lock_work, |
271 | HZ * 10); | 311 | HZ * 10); |
272 | spin_unlock(&vnode->lock); | 312 | spin_unlock(&vnode->lock); |
273 | _leave(" [ext]"); | 313 | _leave(" [ext]"); |
274 | return; | 314 | return; |
275 | 315 | ||
276 | /* If we don't have a granted lock, then we must've been called | 316 | /* If we're waiting for a callback to indicate lock release, we can't |
277 | * back by the server, and so if might be possible to get a | 317 | * actually rely on this, so need to recheck at regular intervals. The |
278 | * lock we're currently waiting for. | 318 | * problem is that the server might not notify us if the lock just |
279 | */ | 319 | * expires (say because a client died) rather than being explicitly |
320 | * released. | ||
321 | */ | ||
280 | case AFS_VNODE_LOCK_WAITING_FOR_CB: | 322 | case AFS_VNODE_LOCK_WAITING_FOR_CB: |
281 | _debug("get"); | 323 | _debug("retry"); |
282 | 324 | afs_next_locker(vnode, 0); | |
283 | key = key_get(vnode->lock_key); | ||
284 | type = vnode->lock_type; | ||
285 | vnode->lock_state = AFS_VNODE_LOCK_SETTING; | ||
286 | spin_unlock(&vnode->lock); | 325 | spin_unlock(&vnode->lock); |
287 | 326 | return; | |
288 | ret = afs_set_lock(vnode, key, type); /* RPC */ | ||
289 | key_put(key); | ||
290 | |||
291 | spin_lock(&vnode->lock); | ||
292 | switch (ret) { | ||
293 | case -EWOULDBLOCK: | ||
294 | _debug("blocked"); | ||
295 | break; | ||
296 | case 0: | ||
297 | _debug("acquired"); | ||
298 | vnode->lock_state = AFS_VNODE_LOCK_GRANTED; | ||
299 | /* Fall through */ | ||
300 | default: | ||
301 | /* Pass the lock or the error onto the first locker in | ||
302 | * the list - if they're looking for this type of lock. | ||
303 | * If they're not, we assume that whoever asked for it | ||
304 | * took a signal. | ||
305 | */ | ||
306 | if (list_empty(&vnode->pending_locks)) { | ||
307 | _debug("withdrawn"); | ||
308 | vnode->lock_state = AFS_VNODE_LOCK_NEED_UNLOCK; | ||
309 | goto again; | ||
310 | } | ||
311 | |||
312 | fl = list_entry(vnode->pending_locks.next, | ||
313 | struct file_lock, fl_u.afs.link); | ||
314 | type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE; | ||
315 | if (vnode->lock_type != type) { | ||
316 | _debug("changed"); | ||
317 | vnode->lock_state = AFS_VNODE_LOCK_NEED_UNLOCK; | ||
318 | goto again; | ||
319 | } | ||
320 | |||
321 | fl->fl_u.afs.state = ret; | ||
322 | if (ret == 0) | ||
323 | afs_grant_locks(vnode, fl); | ||
324 | else | ||
325 | list_del_init(&fl->fl_u.afs.link); | ||
326 | wake_up(&fl->fl_wait); | ||
327 | spin_unlock(&vnode->lock); | ||
328 | _leave(" [granted]"); | ||
329 | return; | ||
330 | } | ||
331 | 327 | ||
332 | default: | 328 | default: |
333 | /* Looks like a lock request was withdrawn. */ | 329 | /* Looks like a lock request was withdrawn. */ |
@@ -345,14 +341,15 @@ again: | |||
345 | */ | 341 | */ |
346 | static void afs_defer_unlock(struct afs_vnode *vnode) | 342 | static void afs_defer_unlock(struct afs_vnode *vnode) |
347 | { | 343 | { |
348 | _enter(""); | 344 | _enter("%u", vnode->lock_state); |
349 | 345 | ||
350 | if (vnode->lock_state == AFS_VNODE_LOCK_GRANTED || | 346 | if (list_empty(&vnode->granted_locks) && |
351 | vnode->lock_state == AFS_VNODE_LOCK_EXTENDING) { | 347 | (vnode->lock_state == AFS_VNODE_LOCK_GRANTED || |
348 | vnode->lock_state == AFS_VNODE_LOCK_EXTENDING)) { | ||
352 | cancel_delayed_work(&vnode->lock_work); | 349 | cancel_delayed_work(&vnode->lock_work); |
353 | 350 | ||
354 | vnode->lock_state = AFS_VNODE_LOCK_NEED_UNLOCK; | 351 | afs_set_lock_state(vnode, AFS_VNODE_LOCK_NEED_UNLOCK); |
355 | afs_lock_may_be_available(vnode); | 352 | queue_delayed_work(afs_lock_manager, &vnode->lock_work, 0); |
356 | } | 353 | } |
357 | } | 354 | } |
358 | 355 | ||
@@ -402,50 +399,6 @@ static int afs_do_setlk_check(struct afs_vnode *vnode, struct key *key, | |||
402 | } | 399 | } |
403 | 400 | ||
404 | /* | 401 | /* |
405 | * Remove the front runner from the pending queue. | ||
406 | * - The caller must hold vnode->lock. | ||
407 | */ | ||
408 | static void afs_dequeue_lock(struct afs_vnode *vnode, struct file_lock *fl) | ||
409 | { | ||
410 | struct file_lock *next; | ||
411 | |||
412 | _enter(""); | ||
413 | |||
414 | /* ->lock_type, ->lock_key and ->lock_state only belong to this | ||
415 | * file_lock if we're at the front of the pending queue or if we have | ||
416 | * the lock granted or if the lock_state is NEED_UNLOCK or UNLOCKING. | ||
417 | */ | ||
418 | if (vnode->granted_locks.next == &fl->fl_u.afs.link && | ||
419 | vnode->granted_locks.prev == &fl->fl_u.afs.link) { | ||
420 | list_del_init(&fl->fl_u.afs.link); | ||
421 | afs_defer_unlock(vnode); | ||
422 | return; | ||
423 | } | ||
424 | |||
425 | if (!list_empty(&vnode->granted_locks) || | ||
426 | vnode->pending_locks.next != &fl->fl_u.afs.link) { | ||
427 | list_del_init(&fl->fl_u.afs.link); | ||
428 | return; | ||
429 | } | ||
430 | |||
431 | list_del_init(&fl->fl_u.afs.link); | ||
432 | key_put(vnode->lock_key); | ||
433 | vnode->lock_key = NULL; | ||
434 | vnode->lock_state = AFS_VNODE_LOCK_NONE; | ||
435 | |||
436 | if (list_empty(&vnode->pending_locks)) | ||
437 | return; | ||
438 | |||
439 | /* The new front of the queue now owns the state variables. */ | ||
440 | next = list_entry(vnode->pending_locks.next, | ||
441 | struct file_lock, fl_u.afs.link); | ||
442 | vnode->lock_key = key_get(afs_file_key(next->fl_file)); | ||
443 | vnode->lock_type = (next->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE; | ||
444 | vnode->lock_state = AFS_VNODE_LOCK_WAITING_FOR_CB; | ||
445 | afs_lock_may_be_available(vnode); | ||
446 | } | ||
447 | |||
448 | /* | ||
449 | * request a lock on a file on the server | 402 | * request a lock on a file on the server |
450 | */ | 403 | */ |
451 | static int afs_do_setlk(struct file *file, struct file_lock *fl) | 404 | static int afs_do_setlk(struct file *file, struct file_lock *fl) |
@@ -469,44 +422,66 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl) | |||
469 | return ret; | 422 | return ret; |
470 | 423 | ||
471 | spin_lock(&vnode->lock); | 424 | spin_lock(&vnode->lock); |
425 | list_add_tail(&fl->fl_u.afs.link, &vnode->pending_locks); | ||
472 | 426 | ||
473 | /* If we've already got a readlock on the server then we instantly | 427 | /* If we've already got a lock on the server then try to move to having |
474 | * grant another readlock, irrespective of whether there are any | 428 | * the VFS grant the requested lock. Note that this means that other |
475 | * pending writelocks. | 429 | * clients may get starved out. |
476 | */ | 430 | */ |
477 | if (type == AFS_LOCK_READ && | 431 | _debug("try %u", vnode->lock_state); |
478 | vnode->lock_state == AFS_VNODE_LOCK_GRANTED && | 432 | if (vnode->lock_state == AFS_VNODE_LOCK_GRANTED) { |
479 | vnode->lock_type == AFS_LOCK_READ) { | 433 | if (type == AFS_LOCK_READ) { |
480 | _debug("instant readlock"); | 434 | _debug("instant readlock"); |
481 | ASSERT(!list_empty(&vnode->granted_locks)); | 435 | list_move_tail(&fl->fl_u.afs.link, &vnode->granted_locks); |
482 | goto share_existing_lock; | 436 | fl->fl_u.afs.state = AFS_LOCK_GRANTED; |
483 | } | 437 | goto vnode_is_locked_u; |
438 | } | ||
484 | 439 | ||
485 | list_add_tail(&fl->fl_u.afs.link, &vnode->pending_locks); | 440 | if (vnode->lock_type == AFS_LOCK_WRITE) { |
441 | _debug("instant writelock"); | ||
442 | list_move_tail(&fl->fl_u.afs.link, &vnode->granted_locks); | ||
443 | fl->fl_u.afs.state = AFS_LOCK_GRANTED; | ||
444 | goto vnode_is_locked_u; | ||
445 | } | ||
446 | } | ||
486 | 447 | ||
487 | if (vnode->lock_state != AFS_VNODE_LOCK_NONE) | 448 | if (vnode->lock_state != AFS_VNODE_LOCK_NONE) |
488 | goto need_to_wait; | 449 | goto need_to_wait; |
489 | 450 | ||
451 | try_to_lock: | ||
490 | /* We don't have a lock on this vnode and we aren't currently waiting | 452 | /* We don't have a lock on this vnode and we aren't currently waiting |
491 | * for one either, so ask the server for a lock. | 453 | * for one either, so ask the server for a lock. |
492 | * | 454 | * |
493 | * Note that we need to be careful if we get interrupted by a signal | 455 | * Note that we need to be careful if we get interrupted by a signal |
494 | * after dispatching the request as we may still get the lock, even | 456 | * after dispatching the request as we may still get the lock, even |
495 | * though we don't wait for the reply (it's not too bad a problem - the | 457 | * though we don't wait for the reply (it's not too bad a problem - the |
496 | * lock will expire in 10 mins anyway). | 458 | * lock will expire in 5 mins anyway). |
497 | */ | 459 | */ |
498 | _debug("not locked"); | 460 | _debug("not locked"); |
499 | vnode->lock_key = key_get(key); | 461 | vnode->lock_key = key_get(key); |
500 | vnode->lock_type = type; | 462 | vnode->lock_type = type; |
501 | vnode->lock_state = AFS_VNODE_LOCK_SETTING; | 463 | afs_set_lock_state(vnode, AFS_VNODE_LOCK_SETTING); |
502 | spin_unlock(&vnode->lock); | 464 | spin_unlock(&vnode->lock); |
503 | 465 | ||
504 | ret = afs_set_lock(vnode, key, type); /* RPC */ | 466 | ret = afs_set_lock(vnode, key, type); /* RPC */ |
505 | 467 | ||
506 | spin_lock(&vnode->lock); | 468 | spin_lock(&vnode->lock); |
507 | switch (ret) { | 469 | switch (ret) { |
470 | case -EKEYREJECTED: | ||
471 | case -EKEYEXPIRED: | ||
472 | case -EKEYREVOKED: | ||
473 | case -EPERM: | ||
474 | case -EACCES: | ||
475 | fl->fl_u.afs.state = ret; | ||
476 | list_del_init(&fl->fl_u.afs.link); | ||
477 | afs_next_locker(vnode, ret); | ||
478 | goto error_unlock; | ||
479 | |||
508 | default: | 480 | default: |
509 | goto abort_attempt; | 481 | fl->fl_u.afs.state = ret; |
482 | list_del_init(&fl->fl_u.afs.link); | ||
483 | afs_next_locker(vnode, 0); | ||
484 | goto error_unlock; | ||
510 | 485 | ||
511 | case -EWOULDBLOCK: | 486 | case -EWOULDBLOCK: |
512 | /* The server doesn't have a lock-waiting queue, so the client | 487 | /* The server doesn't have a lock-waiting queue, so the client |
@@ -516,29 +491,23 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl) | |||
516 | _debug("would block"); | 491 | _debug("would block"); |
517 | ASSERT(list_empty(&vnode->granted_locks)); | 492 | ASSERT(list_empty(&vnode->granted_locks)); |
518 | ASSERTCMP(vnode->pending_locks.next, ==, &fl->fl_u.afs.link); | 493 | ASSERTCMP(vnode->pending_locks.next, ==, &fl->fl_u.afs.link); |
519 | vnode->lock_state = AFS_VNODE_LOCK_WAITING_FOR_CB; | 494 | goto lock_is_contended; |
520 | goto need_to_wait; | ||
521 | 495 | ||
522 | case 0: | 496 | case 0: |
523 | _debug("acquired"); | 497 | _debug("acquired"); |
524 | break; | 498 | afs_set_lock_state(vnode, AFS_VNODE_LOCK_GRANTED); |
499 | afs_grant_locks(vnode); | ||
500 | goto vnode_is_locked_u; | ||
525 | } | 501 | } |
526 | 502 | ||
527 | /* we've acquired a server lock, but it needs to be renewed after 5 | 503 | vnode_is_locked_u: |
528 | * mins */ | ||
529 | vnode->lock_state = AFS_VNODE_LOCK_GRANTED; | ||
530 | afs_schedule_lock_extension(vnode); | ||
531 | |||
532 | share_existing_lock: | ||
533 | /* the lock has been granted as far as we're concerned... */ | ||
534 | fl->fl_u.afs.state = AFS_LOCK_GRANTED; | ||
535 | list_move_tail(&fl->fl_u.afs.link, &vnode->granted_locks); | ||
536 | |||
537 | given_lock: | ||
538 | /* ... but we do still need to get the VFS's blessing */ | ||
539 | spin_unlock(&vnode->lock); | 504 | spin_unlock(&vnode->lock); |
505 | vnode_is_locked: | ||
506 | /* the lock has been granted by the server... */ | ||
507 | ASSERTCMP(fl->fl_u.afs.state, ==, AFS_LOCK_GRANTED); | ||
540 | 508 | ||
541 | ret = posix_lock_file(file, fl, NULL); | 509 | /* ... but the VFS still needs to distribute access on this client. */ |
510 | ret = locks_lock_file_wait(file, fl); | ||
542 | if (ret < 0) | 511 | if (ret < 0) |
543 | goto vfs_rejected_lock; | 512 | goto vfs_rejected_lock; |
544 | 513 | ||
@@ -550,38 +519,61 @@ given_lock: | |||
550 | _leave(" = 0"); | 519 | _leave(" = 0"); |
551 | return 0; | 520 | return 0; |
552 | 521 | ||
522 | lock_is_contended: | ||
523 | if (!(fl->fl_flags & FL_SLEEP)) { | ||
524 | list_del_init(&fl->fl_u.afs.link); | ||
525 | afs_next_locker(vnode, 0); | ||
526 | ret = -EAGAIN; | ||
527 | goto error_unlock; | ||
528 | } | ||
529 | |||
530 | afs_set_lock_state(vnode, AFS_VNODE_LOCK_WAITING_FOR_CB); | ||
531 | queue_delayed_work(afs_lock_manager, &vnode->lock_work, HZ * 5); | ||
532 | |||
553 | need_to_wait: | 533 | need_to_wait: |
554 | /* We're going to have to wait. Either this client doesn't have a lock | 534 | /* We're going to have to wait. Either this client doesn't have a lock |
555 | * on the server yet and we need to wait for a callback to occur, or | 535 | * on the server yet and we need to wait for a callback to occur, or |
556 | * the client does have a lock on the server, but it belongs to some | 536 | * the client does have a lock on the server, but it's shared and we |
557 | * other process(es) and is incompatible with the lock we want. | 537 | * need an exclusive lock. |
558 | */ | 538 | */ |
559 | ret = -EAGAIN; | 539 | spin_unlock(&vnode->lock); |
560 | if (fl->fl_flags & FL_SLEEP) { | ||
561 | spin_unlock(&vnode->lock); | ||
562 | 540 | ||
563 | _debug("sleep"); | 541 | _debug("sleep"); |
564 | ret = wait_event_interruptible(fl->fl_wait, | 542 | ret = wait_event_interruptible(fl->fl_wait, |
565 | fl->fl_u.afs.state != AFS_LOCK_PENDING); | 543 | fl->fl_u.afs.state != AFS_LOCK_PENDING); |
544 | _debug("wait = %d", ret); | ||
566 | 545 | ||
546 | if (fl->fl_u.afs.state >= 0 && fl->fl_u.afs.state != AFS_LOCK_GRANTED) { | ||
567 | spin_lock(&vnode->lock); | 547 | spin_lock(&vnode->lock); |
568 | } | ||
569 | 548 | ||
570 | if (fl->fl_u.afs.state == AFS_LOCK_GRANTED) | 549 | switch (fl->fl_u.afs.state) { |
571 | goto given_lock; | 550 | case AFS_LOCK_YOUR_TRY: |
572 | if (fl->fl_u.afs.state < 0) | 551 | fl->fl_u.afs.state = AFS_LOCK_PENDING; |
573 | ret = fl->fl_u.afs.state; | 552 | goto try_to_lock; |
553 | case AFS_LOCK_PENDING: | ||
554 | if (ret > 0) { | ||
555 | /* We need to retry the lock. We may not be | ||
556 | * notified by the server if it just expired | ||
557 | * rather than being released. | ||
558 | */ | ||
559 | ASSERTCMP(vnode->lock_state, ==, AFS_VNODE_LOCK_WAITING_FOR_CB); | ||
560 | afs_set_lock_state(vnode, AFS_VNODE_LOCK_SETTING); | ||
561 | fl->fl_u.afs.state = AFS_LOCK_PENDING; | ||
562 | goto try_to_lock; | ||
563 | } | ||
564 | goto error_unlock; | ||
565 | case AFS_LOCK_GRANTED: | ||
566 | default: | ||
567 | break; | ||
568 | } | ||
574 | 569 | ||
575 | abort_attempt: | 570 | spin_unlock(&vnode->lock); |
576 | /* we aren't going to get the lock, either because we're unwilling to | 571 | } |
577 | * wait, or because some signal happened */ | ||
578 | _debug("abort"); | ||
579 | afs_dequeue_lock(vnode, fl); | ||
580 | 572 | ||
581 | error_unlock: | 573 | if (fl->fl_u.afs.state == AFS_LOCK_GRANTED) |
582 | spin_unlock(&vnode->lock); | 574 | goto vnode_is_locked; |
583 | _leave(" = %d", ret); | 575 | ret = fl->fl_u.afs.state; |
584 | return ret; | 576 | goto error; |
585 | 577 | ||
586 | vfs_rejected_lock: | 578 | vfs_rejected_lock: |
587 | /* The VFS rejected the lock we just obtained, so we have to discard | 579 | /* The VFS rejected the lock we just obtained, so we have to discard |
@@ -591,9 +583,13 @@ vfs_rejected_lock: | |||
591 | _debug("vfs refused %d", ret); | 583 | _debug("vfs refused %d", ret); |
592 | spin_lock(&vnode->lock); | 584 | spin_lock(&vnode->lock); |
593 | list_del_init(&fl->fl_u.afs.link); | 585 | list_del_init(&fl->fl_u.afs.link); |
594 | if (list_empty(&vnode->granted_locks)) | 586 | afs_defer_unlock(vnode); |
595 | afs_defer_unlock(vnode); | 587 | |
596 | goto error_unlock; | 588 | error_unlock: |
589 | spin_unlock(&vnode->lock); | ||
590 | error: | ||
591 | _leave(" = %d", ret); | ||
592 | return ret; | ||
597 | } | 593 | } |
598 | 594 | ||
599 | /* | 595 | /* |
@@ -609,7 +605,7 @@ static int afs_do_unlk(struct file *file, struct file_lock *fl) | |||
609 | /* Flush all pending writes before doing anything with locks. */ | 605 | /* Flush all pending writes before doing anything with locks. */ |
610 | vfs_fsync(file, 0); | 606 | vfs_fsync(file, 0); |
611 | 607 | ||
612 | ret = posix_lock_file(file, fl, NULL); | 608 | ret = locks_lock_file_wait(file, fl); |
613 | _leave(" = %d [%u]", ret, vnode->lock_state); | 609 | _leave(" = %d [%u]", ret, vnode->lock_state); |
614 | return ret; | 610 | return ret; |
615 | } | 611 | } |
@@ -731,7 +727,11 @@ static void afs_fl_release_private(struct file_lock *fl) | |||
731 | _enter(""); | 727 | _enter(""); |
732 | 728 | ||
733 | spin_lock(&vnode->lock); | 729 | spin_lock(&vnode->lock); |
734 | afs_dequeue_lock(vnode, fl); | 730 | |
731 | list_del_init(&fl->fl_u.afs.link); | ||
732 | if (list_empty(&vnode->granted_locks)) | ||
733 | afs_defer_unlock(vnode); | ||
734 | |||
735 | _debug("state %u for %p", vnode->lock_state, vnode); | 735 | _debug("state %u for %p", vnode->lock_state, vnode); |
736 | spin_unlock(&vnode->lock); | 736 | spin_unlock(&vnode->lock); |
737 | } | 737 | } |