@@ -409,7 +409,7 @@ static void afs_defer_unlock(struct afs_vnode *vnode)
409409 * whether we think that we have a locking permit.
410410 */
411411static 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 )
413413{
414414 afs_access_t access ;
415415 int ret ;
@@ -437,13 +437,9 @@ static int afs_do_setlk_check(struct afs_vnode *vnode, struct key *key,
437437 if (type == AFS_LOCK_READ ) {
438438 if (!(access & (AFS_ACE_INSERT | AFS_ACE_WRITE | AFS_ACE_LOCK )))
439439 return - EACCES ;
440- if (vnode -> status .lock_count == -1 && !can_sleep )
441- return - EAGAIN ; /* Write locked */
442440 } else {
443441 if (!(access & (AFS_ACE_INSERT | AFS_ACE_WRITE )))
444442 return - EACCES ;
445- if (vnode -> status .lock_count != 0 && !can_sleep )
446- return - EAGAIN ; /* Locked */
447443 }
448444
449445 return 0 ;
@@ -456,24 +452,48 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
456452{
457453 struct inode * inode = locks_inode (file );
458454 struct afs_vnode * vnode = AFS_FS_I (inode );
455+ enum afs_flock_mode mode = AFS_FS_S (inode -> i_sb )-> flock_mode ;
459456 afs_lock_type_t type ;
460457 struct key * key = afs_file_key (file );
458+ bool partial , no_server_lock = false;
461459 int ret ;
462460
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 );
464467
465468 fl -> fl_ops = & afs_lock_ops ;
466469 INIT_LIST_HEAD (& fl -> fl_u .afs .link );
467470 fl -> fl_u .afs .state = AFS_LOCK_PENDING ;
468471
472+ partial = (fl -> fl_start != 0 || fl -> fl_end != OFFSET_MAX );
469473 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 ;
470476
471- ret = afs_do_setlk_check (vnode , key , type , fl -> fl_flags & FL_SLEEP );
477+ ret = afs_do_setlk_check (vnode , key , mode , type );
472478 if (ret < 0 )
473479 return ret ;
474480
475481 trace_afs_flock_op (vnode , fl , afs_flock_op_set_lock );
476482
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+
477497 spin_lock (& vnode -> lock );
478498 list_add_tail (& fl -> fl_u .afs .link , & vnode -> pending_locks );
479499
@@ -502,6 +522,18 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
502522 }
503523 }
504524
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+
505537 if (vnode -> lock_state != AFS_VNODE_LOCK_NONE )
506538 goto need_to_wait ;
507539
@@ -571,6 +603,7 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
571603 /* the lock has been granted by the server... */
572604 ASSERTCMP (fl -> fl_u .afs .state , = = , AFS_LOCK_GRANTED );
573605
606+ skip_server_lock :
574607 /* ... but the VFS still needs to distribute access on this client. */
575608 trace_afs_flock_ev (vnode , fl , afs_flock_vfs_locking , 0 );
576609 ret = locks_lock_file_wait (file , fl );
@@ -649,6 +682,8 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
649682 * deal with.
650683 */
651684 _debug ("vfs refused %d" , ret );
685+ if (no_server_lock )
686+ goto error ;
652687 spin_lock (& vnode -> lock );
653688 list_del_init (& fl -> fl_u .afs .link );
654689 afs_defer_unlock (vnode );
0 commit comments