static bool wait_for_ready(struct igt_wakeup *w) { DEFINE_WAIT(ready); set_bit(IDLE, &w->flags); if (atomic_dec_and_test(w->done)) wake_up_var(w->done); if (test_bit(STOP, &w->flags)) goto out; for (;;) { prepare_to_wait(w->wq, &ready, TASK_INTERRUPTIBLE); if (atomic_read(w->ready) == 0) break; schedule(); } finish_wait(w->wq, &ready); out: clear_bit(IDLE, &w->flags); if (atomic_dec_and_test(w->set)) wake_up_var(w->set); return !test_bit(STOP, &w->flags); }
/* * Dispose of a reference on a call. */ void afs_put_call(struct afs_call *call) { struct afs_net *net = call->net; int n = atomic_dec_return(&call->usage); int o = atomic_read(&net->nr_outstanding_calls); trace_afs_call(call, afs_call_trace_put, n + 1, o, __builtin_return_address(0)); ASSERTCMP(n, >=, 0); if (n == 0) { ASSERT(!work_pending(&call->async_work)); ASSERT(call->type->name != NULL); if (call->rxcall) { rxrpc_kernel_end_call(net->socket, call->rxcall); call->rxcall = NULL; } if (call->type->destructor) call->type->destructor(call); afs_put_server(call->net, call->cm_server); afs_put_cb_interest(call->net, call->cbi); kfree(call->request); trace_afs_call(call, afs_call_trace_free, 0, o, __builtin_return_address(0)); kfree(call); o = atomic_dec_return(&net->nr_outstanding_calls); if (o == 0) wake_up_var(&net->nr_outstanding_calls); } }
static bool afs_vl_probe_done(struct afs_vlserver *server) { if (!atomic_dec_and_test(&server->probe_outstanding)) return false; wake_up_var(&server->probe_outstanding); clear_bit_unlock(AFS_VLSERVER_FL_PROBING, &server->flags); wake_up_bit(&server->flags, AFS_VLSERVER_FL_PROBING); return true; }
static void afs_dec_cells_outstanding(struct afs_net *net) { if (atomic_dec_and_test(&net->cells_outstanding)) wake_up_var(&net->cells_outstanding); }
/* * Process the result of probing a vlserver. This is called after successful * or failed delivery of an VL.GetCapabilities operation. */ void afs_vlserver_probe_result(struct afs_call *call) { struct afs_addr_list *alist = call->alist; struct afs_vlserver *server = call->vlserver; unsigned int server_index = call->server_index; unsigned int index = call->addr_ix; unsigned int rtt = UINT_MAX; bool have_result = false; u64 _rtt; int ret = call->error; _enter("%s,%u,%u,%d,%d", server->name, server_index, index, ret, call->abort_code); spin_lock(&server->probe_lock); switch (ret) { case 0: server->probe.error = 0; goto responded; case -ECONNABORTED: if (!server->probe.responded) { server->probe.abort_code = call->abort_code; server->probe.error = ret; } goto responded; case -ENOMEM: case -ENONET: server->probe.local_failure = true; afs_io_error(call, afs_io_error_vl_probe_fail); goto out; case -ECONNRESET: /* Responded, but call expired. */ case -ERFKILL: case -EADDRNOTAVAIL: case -ENETUNREACH: case -EHOSTUNREACH: case -EHOSTDOWN: case -ECONNREFUSED: case -ETIMEDOUT: case -ETIME: default: clear_bit(index, &alist->responded); set_bit(index, &alist->failed); if (!server->probe.responded && (server->probe.error == 0 || server->probe.error == -ETIMEDOUT || server->probe.error == -ETIME)) server->probe.error = ret; afs_io_error(call, afs_io_error_vl_probe_fail); goto out; } responded: set_bit(index, &alist->responded); clear_bit(index, &alist->failed); if (call->service_id == YFS_VL_SERVICE) { server->probe.is_yfs = true; set_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags); alist->addrs[index].srx_service = call->service_id; } else { server->probe.not_yfs = true; if (!server->probe.is_yfs) { clear_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags); alist->addrs[index].srx_service = call->service_id; } } /* Get the RTT and scale it to fit into a 32-bit value that represents * over a minute of time so that we can access it with one instruction * on a 32-bit system. */ _rtt = rxrpc_kernel_get_rtt(call->net->socket, call->rxcall); _rtt /= 64; rtt = (_rtt > UINT_MAX) ? UINT_MAX : _rtt; if (rtt < server->probe.rtt) { server->probe.rtt = rtt; alist->preferred = index; have_result = true; } smp_wmb(); /* Set rtt before responded. */ server->probe.responded = true; set_bit(AFS_VLSERVER_FL_PROBED, &server->flags); out: spin_unlock(&server->probe_lock); _debug("probe [%u][%u] %pISpc rtt=%u ret=%d", server_index, index, &alist->addrs[index].transport, (unsigned int)rtt, ret); have_result |= afs_vl_probe_done(server); if (have_result) { server->probe.have_result = true; wake_up_var(&server->probe.have_result); wake_up_all(&server->probe_wq); } }