again:
_debug("wstate %u for %p", vnode->lock_state, vnode); switch (vnode->lock_state) { case AFS_VNODE_LOCK_NEED_UNLOCK:
afs_set_lock_state(vnode, AFS_VNODE_LOCK_UNLOCKING);
trace_afs_flock_ev(vnode, NULL, afs_flock_work_unlocking, 0);
spin_unlock(&vnode->lock);
/* attempt to release the server lock; if it fails, we just
* wait 5 minutes and it'll expire anyway */
ret = afs_release_lock(vnode, vnode->lock_key); if (ret < 0 && vnode->lock_state != AFS_VNODE_LOCK_DELETED) {
trace_afs_flock_ev(vnode, NULL, afs_flock_release_fail,
ret);
printk(KERN_WARNING "AFS:" " Failed to release lock on {%llx:%llx} error %d\n",
vnode->fid.vid, vnode->fid.vnode, ret);
}
/* If we've already got a lock, then it must be time to extend that *lockasAFSlockstimeoutafter5minutes.
*/ case AFS_VNODE_LOCK_GRANTED:
_debug("extend");
/* If we're waiting for a callback to indicate lock release, we can't *actuallyrelyonthis,soneedtorecheckatregularintervals.The *problemisthattheservermightnotnotifyusifthelockjust *expires(saybecauseaclientdied)ratherthanbeingexplicitly *released.
*/ case AFS_VNODE_LOCK_WAITING_FOR_CB:
_debug("retry");
afs_next_locker(vnode, 0);
spin_unlock(&vnode->lock); return;
case AFS_VNODE_LOCK_DELETED:
afs_kill_lockers_enoent(vnode);
spin_unlock(&vnode->lock); return;
default: /* Looks like a lock request was withdrawn. */
spin_unlock(&vnode->lock);
_leave(" [no]"); return;
}
}
/* Make sure we've got a callback on this file and that our view of the *dataversionisuptodate.
*/
ret = afs_validate(vnode, key); if (ret < 0) return ret;
/* Check the permission set to see if we're actually going to be *allowedtogetalockonthisfile.
*/
ret = afs_check_permit(vnode, key, &access); if (ret < 0) return ret;
/* At a rough estimation, you need LOCK, WRITE or INSERT perm to *read-lockafileandWRITEorINSERTpermtowrite-lockafile. * *Wecan'trelyontheservertodothisforussinceifwewantto *shareareadlockthatwealreadyhave,wewon'tgotheserver.
*/ if (type == AFS_LOCK_READ) { if (!(access & (AFS_ACE_INSERT | AFS_ACE_WRITE | AFS_ACE_LOCK))) return -EACCES;
} else { if (!(access & (AFS_ACE_INSERT | AFS_ACE_WRITE))) return -EACCES;
}
ret = -ENOENT; if (vnode->lock_state == AFS_VNODE_LOCK_DELETED) goto error_unlock;
/* If we've already got a lock on the server then try to move to having *theVFSgranttherequestedlock.Notethatthismeansthatother *clientsmaygetstarvedout.
*/
_debug("try %u", vnode->lock_state); if (vnode->lock_state == AFS_VNODE_LOCK_GRANTED) { if (type == AFS_LOCK_READ) {
_debug("instant readlock");
list_move_tail(&fl->fl_u.afs.link, &vnode->granted_locks);
fl->fl_u.afs.state = AFS_LOCK_GRANTED; goto vnode_is_locked_u;
}
if (vnode->lock_state == AFS_VNODE_LOCK_NONE &&
!(fl->c.flc_flags & FL_SLEEP)) {
ret = -EAGAIN; if (type == AFS_LOCK_READ) { if (vnode->status.lock_count == -1) goto lock_is_contended; /* Write locked */
} else { if (vnode->status.lock_count != 0) goto lock_is_contended; /* Locked */
}
}
if (vnode->lock_state != AFS_VNODE_LOCK_NONE) goto need_to_wait;
try_to_lock: /* We don't have a lock on this vnode and we aren't currently waiting *foroneeither,soasktheserverforalock. * *Notethatweneedtobecarefulifwegetinterruptedbyasignal *afterdispatchingtherequestaswemaystillgetthelock,even *thoughwedon'twaitforthereply(it'snottoobadaproblem-the *lockwillexpirein5minsanyway).
*/
trace_afs_flock_ev(vnode, fl, afs_flock_try_to_lock, 0);
vnode->lock_key = key_get(key);
vnode->lock_type = type;
afs_set_lock_state(vnode, AFS_VNODE_LOCK_SETTING);
spin_unlock(&vnode->lock);
ret = afs_set_lock(vnode, key, type); /* RPC */
spin_lock(&vnode->lock); switch (ret) { case -EKEYREJECTED: case -EKEYEXPIRED: case -EKEYREVOKED: case -EPERM: case -EACCES:
fl->fl_u.afs.state = ret;
trace_afs_flock_ev(vnode, fl, afs_flock_fail_perm, ret);
list_del_init(&fl->fl_u.afs.link);
afs_next_locker(vnode, ret); goto error_unlock;
case -EWOULDBLOCK: /* The server doesn't have a lock-waiting queue, so the client *willhavetoretry.Theserverwillbreaktheoutstanding *callbacksonafilewhenalockisreleased.
*/
ASSERT(list_empty(&vnode->granted_locks));
ASSERTCMP(vnode->pending_locks.next, ==, &fl->fl_u.afs.link); goto lock_is_contended;
vnode_is_locked_u:
spin_unlock(&vnode->lock);
vnode_is_locked: /* the lock has been granted by the server... */
ASSERTCMP(fl->fl_u.afs.state, ==, AFS_LOCK_GRANTED);
skip_server_lock: /* ... but the VFS still needs to distribute access on this client. */
trace_afs_flock_ev(vnode, fl, afs_flock_vfs_locking, 0);
ret = locks_lock_file_wait(file, fl);
trace_afs_flock_ev(vnode, fl, afs_flock_vfs_lock, ret); if (ret < 0) goto vfs_rejected_lock;
/* Again, make sure we've got a callback on this file and, again, make *surethatourviewofthedataversionisuptodate(weignore *errorsincurredhereanddealwiththeconsequenceselsewhere).
*/
afs_validate(vnode, key);
_leave(" = 0"); return0;
lock_is_contended: if (!(fl->c.flc_flags & FL_SLEEP)) {
list_del_init(&fl->fl_u.afs.link);
afs_next_locker(vnode, 0);
ret = -EAGAIN; goto error_unlock;
}
need_to_wait: /* We're going to have to wait. Either this client doesn't have a lock *ontheserveryetandweneedtowaitforacallbacktooccur,or *theclientdoeshavealockontheserver,butit'ssharedandwe *needanexclusivelock.
*/
spin_unlock(&vnode->lock);
if (fl->fl_u.afs.state >= 0 && fl->fl_u.afs.state != AFS_LOCK_GRANTED) {
spin_lock(&vnode->lock);
switch (fl->fl_u.afs.state) { case AFS_LOCK_YOUR_TRY:
fl->fl_u.afs.state = AFS_LOCK_PENDING; goto try_to_lock; case AFS_LOCK_PENDING: if (ret > 0) { /* We need to retry the lock. We may not be *notifiedbytheserverifitjustexpired *ratherthanbeingreleased.
*/
ASSERTCMP(vnode->lock_state, ==, AFS_VNODE_LOCK_WAITING_FOR_CB);
afs_set_lock_state(vnode, AFS_VNODE_LOCK_SETTING);
fl->fl_u.afs.state = AFS_LOCK_PENDING; goto try_to_lock;
} goto error_unlock; case AFS_LOCK_GRANTED: default: break;
}
spin_unlock(&vnode->lock);
}
if (fl->fl_u.afs.state == AFS_LOCK_GRANTED) goto vnode_is_locked;
ret = fl->fl_u.afs.state; goto error;
vfs_rejected_lock: /* The VFS rejected the lock we just obtained, so we have to discard *whatwejustgot.Wedeferthistothelockmanagerworkitemto *dealwith.
*/
_debug("vfs refused %d", ret); if (no_server_lock) goto error;
spin_lock(&vnode->lock);
list_del_init(&fl->fl_u.afs.link);
afs_defer_unlock(vnode);
if (vnode->lock_state == AFS_VNODE_LOCK_DELETED) return -ENOENT;
fl->c.flc_type = F_UNLCK;
/* check local lock records first */
posix_test_lock(file, fl); if (lock_is_unlock(fl)) { /* no local locks; consult the server */
ret = afs_fetch_status(vnode, key, false, NULL); if (ret < 0) goto error;
/* we're simulating flock() locks using posix locks on the server */ if (lock_is_unlock(fl))
ret = afs_do_unlk(file, fl); else
ret = afs_do_setlk(file, fl);
switch (ret) { case0: op = afs_flock_op_return_ok; break; case -EAGAIN: op = afs_flock_op_return_eagain; break; case -EDEADLK: op = afs_flock_op_return_edeadlk; break; default: op = afs_flock_op_return_error; break;
}
trace_afs_flock_op(vnode, fl, op); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.