// SPDX-License-Identifier: GPL-2.0-or-later /* Fileserver-directed operation handling. * * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com)
*/
/* * Unlock the I/O lock on a vnode.
*/ staticvoid afs_unlock_for_io(struct afs_vnode *vnode)
{ struct afs_io_locker *locker;
spin_lock(&vnode->lock);
locker = list_first_entry_or_null(&vnode->io_lock_waiters, struct afs_io_locker, link); if (locker) {
list_del(&locker->link);
smp_store_release(&locker->have_lock, 1); /* The unlock barrier. */
smp_mb__after_atomic(); /* Store have_lock before task state */
wake_up_process(locker->task);
} else {
clear_bit(AFS_VNODE_IO_LOCK, &vnode->flags);
}
spin_unlock(&vnode->lock);
}
/* * Lock the I/O lock on a vnode uninterruptibly. We can't use an ordinary * mutex as lockdep will complain if we unlock it in the wrong thread.
*/ staticvoid afs_lock_for_io(struct afs_vnode *vnode)
{ struct afs_io_locker myself = { .task = current, };
spin_lock(&vnode->lock);
if (!test_and_set_bit(AFS_VNODE_IO_LOCK, &vnode->flags)) {
spin_unlock(&vnode->lock); return;
}
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE); if (smp_load_acquire(&myself.have_lock)) /* The lock barrier */ break;
schedule();
}
__set_current_state(TASK_RUNNING);
}
/* * Lock the I/O lock on a vnode interruptibly. We can't use an ordinary mutex * as lockdep will complain if we unlock it in the wrong thread.
*/ staticint afs_lock_for_io_interruptible(struct afs_vnode *vnode)
{ struct afs_io_locker myself = { .task = current, }; int ret = 0;
spin_lock(&vnode->lock);
if (!test_and_set_bit(AFS_VNODE_IO_LOCK, &vnode->flags)) {
spin_unlock(&vnode->lock); return 0;
}
for (;;) {
set_current_state(TASK_INTERRUPTIBLE); if (smp_load_acquire(&myself.have_lock) || /* The lock barrier */
signal_pending(current)) break;
schedule();
}
__set_current_state(TASK_RUNNING);
/* If we got a signal, try to transfer the lock onto the next * waiter.
*/ if (unlikely(signal_pending(current))) {
spin_lock(&vnode->lock); if (myself.have_lock) {
spin_unlock(&vnode->lock);
afs_unlock_for_io(vnode);
} else {
list_del(&myself.link);
spin_unlock(&vnode->lock);
}
ret = -ERESTARTSYS;
} return ret;
}
if (vnode) {
vp->fid = vnode->fid;
vp->dv_before = vnode->status.data_version;
vp->cb_break_before = afs_calc_vnode_cb_break(vnode); if (vnode->lock_state != AFS_VNODE_LOCK_NONE)
op->flags |= AFS_OPERATION_CUR_ONLY; if (vp->modification)
set_bit(AFS_VNODE_MODIFYING, &vnode->flags);
}
if (vp->fid.vnode)
_debug("PREP[%u] {%llx:%llu.%u}",
index, vp->fid.vid, vp->fid.vnode, vp->fid.unique);
}
/* * Begin an operation on the fileserver. * * Fileserver operations are serialised on the server by vnode, so we serialise * them here also using the io_lock.
*/ bool afs_begin_vnode_operation(struct afs_operation *op)
{ struct afs_vnode *vnode = op->file[0].vnode;
ASSERT(vnode);
_enter("");
if (op->file[0].need_io_lock) if (!afs_get_io_locks(op)) returnfalse;
if (op->call_responded && op->server)
set_bit(AFS_SERVER_FL_RESPONDING, &op->server->flags);
if (!afs_op_error(op)) {
_debug("success");
op->ops->success(op);
} elseif (op->cumul_error.aborted) { if (op->ops->aborted)
op->ops->aborted(op);
} else { if (op->ops->failed)
op->ops->failed(op);
}
afs_end_vnode_operation(op);
if (!afs_op_error(op) && op->ops->edit_dir) {
_debug("edit_dir");
op->ops->edit_dir(op);
}
_leave("");
}
/* * Dispose of an operation.
*/ int afs_put_operation(struct afs_operation *op)
{ struct afs_addr_list *alist; int i, ret = afs_op_error(op);
_enter("op=%08x,%d", op->debug_id, ret);
if (op->ops && op->ops->put)
op->ops->put(op); if (op->file[0].modification)
clear_bit(AFS_VNODE_MODIFYING, &op->file[0].vnode->flags); if (op->file[1].modification && op->file[1].vnode != op->file[0].vnode)
clear_bit(AFS_VNODE_MODIFYING, &op->file[1].vnode->flags); if (op->file[0].put_vnode)
iput(&op->file[0].vnode->netfs.inode); if (op->file[1].put_vnode)
iput(&op->file[1].vnode->netfs.inode);
if (op->more_files) { for (i = 0; i < op->nr_files - 2; i++) if (op->more_files[i].put_vnode)
iput(&op->more_files[i].vnode->netfs.inode);
kfree(op->more_files);
}
if (op->estate) {
alist = op->estate->addresses; if (alist) { if (op->call_responded &&
op->addr_index != alist->preferred &&
test_bit(alist->preferred, &op->addr_tried))
WRITE_ONCE(alist->preferred, op->addr_index);
}
}
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.