summaryrefslogtreecommitdiffstats
path: root/fs/afs/flock.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/afs/flock.c')
-rw-r--r--fs/afs/flock.c49
1 files changed, 42 insertions, 7 deletions
diff --git a/fs/afs/flock.c b/fs/afs/flock.c
index 325bf731d8dd..ef313f4c1d11 100644
--- a/fs/afs/flock.c
+++ b/fs/afs/flock.c
@@ -409,7 +409,7 @@ static void afs_defer_unlock(struct afs_vnode *vnode)
409 * whether we think that we have a locking permit. 409 * whether we think that we have a locking permit.
410 */ 410 */
411static int afs_do_setlk_check(struct afs_vnode *vnode, struct key *key, 411static int afs_do_setlk_check(struct afs_vnode *vnode, struct key *key,
412 afs_lock_type_t type, bool can_sleep) 412 enum afs_flock_mode mode, afs_lock_type_t type)
413{ 413{
414 afs_access_t access; 414 afs_access_t access;
415 int ret; 415 int ret;
@@ -437,13 +437,9 @@ static int afs_do_setlk_check(struct afs_vnode *vnode, struct key *key,
437 if (type == AFS_LOCK_READ) { 437 if (type == AFS_LOCK_READ) {
438 if (!(access & (AFS_ACE_INSERT | AFS_ACE_WRITE | AFS_ACE_LOCK))) 438 if (!(access & (AFS_ACE_INSERT | AFS_ACE_WRITE | AFS_ACE_LOCK)))
439 return -EACCES; 439 return -EACCES;
440 if (vnode->status.lock_count == -1 && !can_sleep)
441 return -EAGAIN; /* Write locked */
442 } else { 440 } else {
443 if (!(access & (AFS_ACE_INSERT | AFS_ACE_WRITE))) 441 if (!(access & (AFS_ACE_INSERT | AFS_ACE_WRITE)))
444 return -EACCES; 442 return -EACCES;
445 if (vnode->status.lock_count != 0 && !can_sleep)
446 return -EAGAIN; /* Locked */
447 } 443 }
448 444
449 return 0; 445 return 0;
@@ -456,24 +452,48 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
456{ 452{
457 struct inode *inode = locks_inode(file); 453 struct inode *inode = locks_inode(file);
458 struct afs_vnode *vnode = AFS_FS_I(inode); 454 struct afs_vnode *vnode = AFS_FS_I(inode);
455 enum afs_flock_mode mode = AFS_FS_S(inode->i_sb)->flock_mode;
459 afs_lock_type_t type; 456 afs_lock_type_t type;
460 struct key *key = afs_file_key(file); 457 struct key *key = afs_file_key(file);
458 bool partial, no_server_lock = false;
461 int ret; 459 int ret;
462 460
463 _enter("{%llx:%llu},%u", vnode->fid.vid, vnode->fid.vnode, fl->fl_type); 461 if (mode == afs_flock_mode_unset)
462 mode = afs_flock_mode_openafs;
463
464 _enter("{%llx:%llu},%llu-%llu,%u,%u",
465 vnode->fid.vid, vnode->fid.vnode,
466 fl->fl_start, fl->fl_end, fl->fl_type, mode);
464 467
465 fl->fl_ops = &afs_lock_ops; 468 fl->fl_ops = &afs_lock_ops;
466 INIT_LIST_HEAD(&fl->fl_u.afs.link); 469 INIT_LIST_HEAD(&fl->fl_u.afs.link);
467 fl->fl_u.afs.state = AFS_LOCK_PENDING; 470 fl->fl_u.afs.state = AFS_LOCK_PENDING;
468 471
472 partial = (fl->fl_start != 0 || fl->fl_end != OFFSET_MAX);
469 type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE; 473 type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
474 if (mode == afs_flock_mode_write && partial)
475 type = AFS_LOCK_WRITE;
470 476
471 ret = afs_do_setlk_check(vnode, key, type, fl->fl_flags & FL_SLEEP); 477 ret = afs_do_setlk_check(vnode, key, mode, type);
472 if (ret < 0) 478 if (ret < 0)
473 return ret; 479 return ret;
474 480
475 trace_afs_flock_op(vnode, fl, afs_flock_op_set_lock); 481 trace_afs_flock_op(vnode, fl, afs_flock_op_set_lock);
476 482
483 /* AFS3 protocol only supports full-file locks and doesn't provide any
484 * method of upgrade/downgrade, so we need to emulate for partial-file
485 * locks.
486 *
487 * The OpenAFS client only gets a server lock for a full-file lock and
488 * keeps partial-file locks local. Allow this behaviour to be emulated
489 * (as the default).
490 */
491 if (mode == afs_flock_mode_local ||
492 (partial && mode == afs_flock_mode_openafs)) {
493 no_server_lock = true;
494 goto skip_server_lock;
495 }
496
477 spin_lock(&vnode->lock); 497 spin_lock(&vnode->lock);
478 list_add_tail(&fl->fl_u.afs.link, &vnode->pending_locks); 498 list_add_tail(&fl->fl_u.afs.link, &vnode->pending_locks);
479 499
@@ -502,6 +522,18 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
502 } 522 }
503 } 523 }
504 524
525 if (vnode->lock_state == AFS_VNODE_LOCK_NONE &&
526 !(fl->fl_flags & FL_SLEEP)) {
527 ret = -EAGAIN;
528 if (type == AFS_LOCK_READ) {
529 if (vnode->status.lock_count == -1)
530 goto lock_is_contended; /* Write locked */
531 } else {
532 if (vnode->status.lock_count != 0)
533 goto lock_is_contended; /* Locked */
534 }
535 }
536
505 if (vnode->lock_state != AFS_VNODE_LOCK_NONE) 537 if (vnode->lock_state != AFS_VNODE_LOCK_NONE)
506 goto need_to_wait; 538 goto need_to_wait;
507 539
@@ -571,6 +603,7 @@ vnode_is_locked:
571 /* the lock has been granted by the server... */ 603 /* the lock has been granted by the server... */
572 ASSERTCMP(fl->fl_u.afs.state, ==, AFS_LOCK_GRANTED); 604 ASSERTCMP(fl->fl_u.afs.state, ==, AFS_LOCK_GRANTED);
573 605
606skip_server_lock:
574 /* ... but the VFS still needs to distribute access on this client. */ 607 /* ... but the VFS still needs to distribute access on this client. */
575 trace_afs_flock_ev(vnode, fl, afs_flock_vfs_locking, 0); 608 trace_afs_flock_ev(vnode, fl, afs_flock_vfs_locking, 0);
576 ret = locks_lock_file_wait(file, fl); 609 ret = locks_lock_file_wait(file, fl);
@@ -649,6 +682,8 @@ vfs_rejected_lock:
649 * deal with. 682 * deal with.
650 */ 683 */
651 _debug("vfs refused %d", ret); 684 _debug("vfs refused %d", ret);
685 if (no_server_lock)
686 goto error;
652 spin_lock(&vnode->lock); 687 spin_lock(&vnode->lock);
653 list_del_init(&fl->fl_u.afs.link); 688 list_del_init(&fl->fl_u.afs.link);
654 afs_defer_unlock(vnode); 689 afs_defer_unlock(vnode);