162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* AFS Cache Manager Service
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/init.h>
1062306a36Sopenharmony_ci#include <linux/slab.h>
1162306a36Sopenharmony_ci#include <linux/sched.h>
1262306a36Sopenharmony_ci#include <linux/ip.h>
1362306a36Sopenharmony_ci#include "internal.h"
1462306a36Sopenharmony_ci#include "afs_cm.h"
1562306a36Sopenharmony_ci#include "protocol_yfs.h"
1662306a36Sopenharmony_ci#define RXRPC_TRACE_ONLY_DEFINE_ENUMS
1762306a36Sopenharmony_ci#include <trace/events/rxrpc.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic int afs_deliver_cb_init_call_back_state(struct afs_call *);
2062306a36Sopenharmony_cistatic int afs_deliver_cb_init_call_back_state3(struct afs_call *);
2162306a36Sopenharmony_cistatic int afs_deliver_cb_probe(struct afs_call *);
2262306a36Sopenharmony_cistatic int afs_deliver_cb_callback(struct afs_call *);
2362306a36Sopenharmony_cistatic int afs_deliver_cb_probe_uuid(struct afs_call *);
2462306a36Sopenharmony_cistatic int afs_deliver_cb_tell_me_about_yourself(struct afs_call *);
2562306a36Sopenharmony_cistatic void afs_cm_destructor(struct afs_call *);
2662306a36Sopenharmony_cistatic void SRXAFSCB_CallBack(struct work_struct *);
2762306a36Sopenharmony_cistatic void SRXAFSCB_InitCallBackState(struct work_struct *);
2862306a36Sopenharmony_cistatic void SRXAFSCB_Probe(struct work_struct *);
2962306a36Sopenharmony_cistatic void SRXAFSCB_ProbeUuid(struct work_struct *);
3062306a36Sopenharmony_cistatic void SRXAFSCB_TellMeAboutYourself(struct work_struct *);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic int afs_deliver_yfs_cb_callback(struct afs_call *);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/*
3562306a36Sopenharmony_ci * CB.CallBack operation type
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_cistatic const struct afs_call_type afs_SRXCBCallBack = {
3862306a36Sopenharmony_ci	.name		= "CB.CallBack",
3962306a36Sopenharmony_ci	.deliver	= afs_deliver_cb_callback,
4062306a36Sopenharmony_ci	.destructor	= afs_cm_destructor,
4162306a36Sopenharmony_ci	.work		= SRXAFSCB_CallBack,
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/*
4562306a36Sopenharmony_ci * CB.InitCallBackState operation type
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_cistatic const struct afs_call_type afs_SRXCBInitCallBackState = {
4862306a36Sopenharmony_ci	.name		= "CB.InitCallBackState",
4962306a36Sopenharmony_ci	.deliver	= afs_deliver_cb_init_call_back_state,
5062306a36Sopenharmony_ci	.destructor	= afs_cm_destructor,
5162306a36Sopenharmony_ci	.work		= SRXAFSCB_InitCallBackState,
5262306a36Sopenharmony_ci};
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/*
5562306a36Sopenharmony_ci * CB.InitCallBackState3 operation type
5662306a36Sopenharmony_ci */
5762306a36Sopenharmony_cistatic const struct afs_call_type afs_SRXCBInitCallBackState3 = {
5862306a36Sopenharmony_ci	.name		= "CB.InitCallBackState3",
5962306a36Sopenharmony_ci	.deliver	= afs_deliver_cb_init_call_back_state3,
6062306a36Sopenharmony_ci	.destructor	= afs_cm_destructor,
6162306a36Sopenharmony_ci	.work		= SRXAFSCB_InitCallBackState,
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/*
6562306a36Sopenharmony_ci * CB.Probe operation type
6662306a36Sopenharmony_ci */
6762306a36Sopenharmony_cistatic const struct afs_call_type afs_SRXCBProbe = {
6862306a36Sopenharmony_ci	.name		= "CB.Probe",
6962306a36Sopenharmony_ci	.deliver	= afs_deliver_cb_probe,
7062306a36Sopenharmony_ci	.destructor	= afs_cm_destructor,
7162306a36Sopenharmony_ci	.work		= SRXAFSCB_Probe,
7262306a36Sopenharmony_ci};
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/*
7562306a36Sopenharmony_ci * CB.ProbeUuid operation type
7662306a36Sopenharmony_ci */
7762306a36Sopenharmony_cistatic const struct afs_call_type afs_SRXCBProbeUuid = {
7862306a36Sopenharmony_ci	.name		= "CB.ProbeUuid",
7962306a36Sopenharmony_ci	.deliver	= afs_deliver_cb_probe_uuid,
8062306a36Sopenharmony_ci	.destructor	= afs_cm_destructor,
8162306a36Sopenharmony_ci	.work		= SRXAFSCB_ProbeUuid,
8262306a36Sopenharmony_ci};
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/*
8562306a36Sopenharmony_ci * CB.TellMeAboutYourself operation type
8662306a36Sopenharmony_ci */
8762306a36Sopenharmony_cistatic const struct afs_call_type afs_SRXCBTellMeAboutYourself = {
8862306a36Sopenharmony_ci	.name		= "CB.TellMeAboutYourself",
8962306a36Sopenharmony_ci	.deliver	= afs_deliver_cb_tell_me_about_yourself,
9062306a36Sopenharmony_ci	.destructor	= afs_cm_destructor,
9162306a36Sopenharmony_ci	.work		= SRXAFSCB_TellMeAboutYourself,
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/*
9562306a36Sopenharmony_ci * YFS CB.CallBack operation type
9662306a36Sopenharmony_ci */
9762306a36Sopenharmony_cistatic const struct afs_call_type afs_SRXYFSCB_CallBack = {
9862306a36Sopenharmony_ci	.name		= "YFSCB.CallBack",
9962306a36Sopenharmony_ci	.deliver	= afs_deliver_yfs_cb_callback,
10062306a36Sopenharmony_ci	.destructor	= afs_cm_destructor,
10162306a36Sopenharmony_ci	.work		= SRXAFSCB_CallBack,
10262306a36Sopenharmony_ci};
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/*
10562306a36Sopenharmony_ci * route an incoming cache manager call
10662306a36Sopenharmony_ci * - return T if supported, F if not
10762306a36Sopenharmony_ci */
10862306a36Sopenharmony_cibool afs_cm_incoming_call(struct afs_call *call)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	_enter("{%u, CB.OP %u}", call->service_id, call->operation_ID);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	switch (call->operation_ID) {
11362306a36Sopenharmony_ci	case CBCallBack:
11462306a36Sopenharmony_ci		call->type = &afs_SRXCBCallBack;
11562306a36Sopenharmony_ci		return true;
11662306a36Sopenharmony_ci	case CBInitCallBackState:
11762306a36Sopenharmony_ci		call->type = &afs_SRXCBInitCallBackState;
11862306a36Sopenharmony_ci		return true;
11962306a36Sopenharmony_ci	case CBInitCallBackState3:
12062306a36Sopenharmony_ci		call->type = &afs_SRXCBInitCallBackState3;
12162306a36Sopenharmony_ci		return true;
12262306a36Sopenharmony_ci	case CBProbe:
12362306a36Sopenharmony_ci		call->type = &afs_SRXCBProbe;
12462306a36Sopenharmony_ci		return true;
12562306a36Sopenharmony_ci	case CBProbeUuid:
12662306a36Sopenharmony_ci		call->type = &afs_SRXCBProbeUuid;
12762306a36Sopenharmony_ci		return true;
12862306a36Sopenharmony_ci	case CBTellMeAboutYourself:
12962306a36Sopenharmony_ci		call->type = &afs_SRXCBTellMeAboutYourself;
13062306a36Sopenharmony_ci		return true;
13162306a36Sopenharmony_ci	case YFSCBCallBack:
13262306a36Sopenharmony_ci		if (call->service_id != YFS_CM_SERVICE)
13362306a36Sopenharmony_ci			return false;
13462306a36Sopenharmony_ci		call->type = &afs_SRXYFSCB_CallBack;
13562306a36Sopenharmony_ci		return true;
13662306a36Sopenharmony_ci	default:
13762306a36Sopenharmony_ci		return false;
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/*
14262306a36Sopenharmony_ci * Find the server record by peer address and record a probe to the cache
14362306a36Sopenharmony_ci * manager from a server.
14462306a36Sopenharmony_ci */
14562306a36Sopenharmony_cistatic int afs_find_cm_server_by_peer(struct afs_call *call)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	struct sockaddr_rxrpc srx;
14862306a36Sopenharmony_ci	struct afs_server *server;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	server = afs_find_server(call->net, &srx);
15362306a36Sopenharmony_ci	if (!server) {
15462306a36Sopenharmony_ci		trace_afs_cm_no_server(call, &srx);
15562306a36Sopenharmony_ci		return 0;
15662306a36Sopenharmony_ci	}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	call->server = server;
15962306a36Sopenharmony_ci	return 0;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci/*
16362306a36Sopenharmony_ci * Find the server record by server UUID and record a probe to the cache
16462306a36Sopenharmony_ci * manager from a server.
16562306a36Sopenharmony_ci */
16662306a36Sopenharmony_cistatic int afs_find_cm_server_by_uuid(struct afs_call *call,
16762306a36Sopenharmony_ci				      struct afs_uuid *uuid)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct afs_server *server;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	rcu_read_lock();
17262306a36Sopenharmony_ci	server = afs_find_server_by_uuid(call->net, call->request);
17362306a36Sopenharmony_ci	rcu_read_unlock();
17462306a36Sopenharmony_ci	if (!server) {
17562306a36Sopenharmony_ci		trace_afs_cm_no_server_u(call, call->request);
17662306a36Sopenharmony_ci		return 0;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	call->server = server;
18062306a36Sopenharmony_ci	return 0;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/*
18462306a36Sopenharmony_ci * Clean up a cache manager call.
18562306a36Sopenharmony_ci */
18662306a36Sopenharmony_cistatic void afs_cm_destructor(struct afs_call *call)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	kfree(call->buffer);
18962306a36Sopenharmony_ci	call->buffer = NULL;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/*
19362306a36Sopenharmony_ci * Abort a service call from within an action function.
19462306a36Sopenharmony_ci */
19562306a36Sopenharmony_cistatic void afs_abort_service_call(struct afs_call *call, u32 abort_code, int error,
19662306a36Sopenharmony_ci				   enum rxrpc_abort_reason why)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
19962306a36Sopenharmony_ci				abort_code, error, why);
20062306a36Sopenharmony_ci	afs_set_call_complete(call, error, 0);
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci/*
20462306a36Sopenharmony_ci * The server supplied a list of callbacks that it wanted to break.
20562306a36Sopenharmony_ci */
20662306a36Sopenharmony_cistatic void SRXAFSCB_CallBack(struct work_struct *work)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct afs_call *call = container_of(work, struct afs_call, work);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	_enter("");
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/* We need to break the callbacks before sending the reply as the
21362306a36Sopenharmony_ci	 * server holds up change visibility till it receives our reply so as
21462306a36Sopenharmony_ci	 * to maintain cache coherency.
21562306a36Sopenharmony_ci	 */
21662306a36Sopenharmony_ci	if (call->server) {
21762306a36Sopenharmony_ci		trace_afs_server(call->server->debug_id,
21862306a36Sopenharmony_ci				 refcount_read(&call->server->ref),
21962306a36Sopenharmony_ci				 atomic_read(&call->server->active),
22062306a36Sopenharmony_ci				 afs_server_trace_callback);
22162306a36Sopenharmony_ci		afs_break_callbacks(call->server, call->count, call->request);
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	afs_send_empty_reply(call);
22562306a36Sopenharmony_ci	afs_put_call(call);
22662306a36Sopenharmony_ci	_leave("");
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci/*
23062306a36Sopenharmony_ci * deliver request data to a CB.CallBack call
23162306a36Sopenharmony_ci */
23262306a36Sopenharmony_cistatic int afs_deliver_cb_callback(struct afs_call *call)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	struct afs_callback_break *cb;
23562306a36Sopenharmony_ci	__be32 *bp;
23662306a36Sopenharmony_ci	int ret, loop;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	_enter("{%u}", call->unmarshall);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	switch (call->unmarshall) {
24162306a36Sopenharmony_ci	case 0:
24262306a36Sopenharmony_ci		afs_extract_to_tmp(call);
24362306a36Sopenharmony_ci		call->unmarshall++;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci		/* extract the FID array and its count in two steps */
24662306a36Sopenharmony_ci		fallthrough;
24762306a36Sopenharmony_ci	case 1:
24862306a36Sopenharmony_ci		_debug("extract FID count");
24962306a36Sopenharmony_ci		ret = afs_extract_data(call, true);
25062306a36Sopenharmony_ci		if (ret < 0)
25162306a36Sopenharmony_ci			return ret;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci		call->count = ntohl(call->tmp);
25462306a36Sopenharmony_ci		_debug("FID count: %u", call->count);
25562306a36Sopenharmony_ci		if (call->count > AFSCBMAX)
25662306a36Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_cb_fid_count);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		call->buffer = kmalloc(array3_size(call->count, 3, 4),
25962306a36Sopenharmony_ci				       GFP_KERNEL);
26062306a36Sopenharmony_ci		if (!call->buffer)
26162306a36Sopenharmony_ci			return -ENOMEM;
26262306a36Sopenharmony_ci		afs_extract_to_buf(call, call->count * 3 * 4);
26362306a36Sopenharmony_ci		call->unmarshall++;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci		fallthrough;
26662306a36Sopenharmony_ci	case 2:
26762306a36Sopenharmony_ci		_debug("extract FID array");
26862306a36Sopenharmony_ci		ret = afs_extract_data(call, true);
26962306a36Sopenharmony_ci		if (ret < 0)
27062306a36Sopenharmony_ci			return ret;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		_debug("unmarshall FID array");
27362306a36Sopenharmony_ci		call->request = kcalloc(call->count,
27462306a36Sopenharmony_ci					sizeof(struct afs_callback_break),
27562306a36Sopenharmony_ci					GFP_KERNEL);
27662306a36Sopenharmony_ci		if (!call->request)
27762306a36Sopenharmony_ci			return -ENOMEM;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		cb = call->request;
28062306a36Sopenharmony_ci		bp = call->buffer;
28162306a36Sopenharmony_ci		for (loop = call->count; loop > 0; loop--, cb++) {
28262306a36Sopenharmony_ci			cb->fid.vid	= ntohl(*bp++);
28362306a36Sopenharmony_ci			cb->fid.vnode	= ntohl(*bp++);
28462306a36Sopenharmony_ci			cb->fid.unique	= ntohl(*bp++);
28562306a36Sopenharmony_ci		}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci		afs_extract_to_tmp(call);
28862306a36Sopenharmony_ci		call->unmarshall++;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci		/* extract the callback array and its count in two steps */
29162306a36Sopenharmony_ci		fallthrough;
29262306a36Sopenharmony_ci	case 3:
29362306a36Sopenharmony_ci		_debug("extract CB count");
29462306a36Sopenharmony_ci		ret = afs_extract_data(call, true);
29562306a36Sopenharmony_ci		if (ret < 0)
29662306a36Sopenharmony_ci			return ret;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci		call->count2 = ntohl(call->tmp);
29962306a36Sopenharmony_ci		_debug("CB count: %u", call->count2);
30062306a36Sopenharmony_ci		if (call->count2 != call->count && call->count2 != 0)
30162306a36Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_cb_count);
30262306a36Sopenharmony_ci		call->iter = &call->def_iter;
30362306a36Sopenharmony_ci		iov_iter_discard(&call->def_iter, ITER_DEST, call->count2 * 3 * 4);
30462306a36Sopenharmony_ci		call->unmarshall++;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci		fallthrough;
30762306a36Sopenharmony_ci	case 4:
30862306a36Sopenharmony_ci		_debug("extract discard %zu/%u",
30962306a36Sopenharmony_ci		       iov_iter_count(call->iter), call->count2 * 3 * 4);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci		ret = afs_extract_data(call, false);
31262306a36Sopenharmony_ci		if (ret < 0)
31362306a36Sopenharmony_ci			return ret;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		call->unmarshall++;
31662306a36Sopenharmony_ci		fallthrough;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	case 5:
31962306a36Sopenharmony_ci		break;
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
32362306a36Sopenharmony_ci		return afs_io_error(call, afs_io_error_cm_reply);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	/* we'll need the file server record as that tells us which set of
32662306a36Sopenharmony_ci	 * vnodes to operate upon */
32762306a36Sopenharmony_ci	return afs_find_cm_server_by_peer(call);
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci/*
33162306a36Sopenharmony_ci * allow the fileserver to request callback state (re-)initialisation
33262306a36Sopenharmony_ci */
33362306a36Sopenharmony_cistatic void SRXAFSCB_InitCallBackState(struct work_struct *work)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct afs_call *call = container_of(work, struct afs_call, work);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	_enter("{%p}", call->server);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (call->server)
34062306a36Sopenharmony_ci		afs_init_callback_state(call->server);
34162306a36Sopenharmony_ci	afs_send_empty_reply(call);
34262306a36Sopenharmony_ci	afs_put_call(call);
34362306a36Sopenharmony_ci	_leave("");
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci/*
34762306a36Sopenharmony_ci * deliver request data to a CB.InitCallBackState call
34862306a36Sopenharmony_ci */
34962306a36Sopenharmony_cistatic int afs_deliver_cb_init_call_back_state(struct afs_call *call)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	int ret;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	_enter("");
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	afs_extract_discard(call, 0);
35662306a36Sopenharmony_ci	ret = afs_extract_data(call, false);
35762306a36Sopenharmony_ci	if (ret < 0)
35862306a36Sopenharmony_ci		return ret;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	/* we'll need the file server record as that tells us which set of
36162306a36Sopenharmony_ci	 * vnodes to operate upon */
36262306a36Sopenharmony_ci	return afs_find_cm_server_by_peer(call);
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci/*
36662306a36Sopenharmony_ci * deliver request data to a CB.InitCallBackState3 call
36762306a36Sopenharmony_ci */
36862306a36Sopenharmony_cistatic int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct afs_uuid *r;
37162306a36Sopenharmony_ci	unsigned loop;
37262306a36Sopenharmony_ci	__be32 *b;
37362306a36Sopenharmony_ci	int ret;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	_enter("");
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	_enter("{%u}", call->unmarshall);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	switch (call->unmarshall) {
38062306a36Sopenharmony_ci	case 0:
38162306a36Sopenharmony_ci		call->buffer = kmalloc_array(11, sizeof(__be32), GFP_KERNEL);
38262306a36Sopenharmony_ci		if (!call->buffer)
38362306a36Sopenharmony_ci			return -ENOMEM;
38462306a36Sopenharmony_ci		afs_extract_to_buf(call, 11 * sizeof(__be32));
38562306a36Sopenharmony_ci		call->unmarshall++;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci		fallthrough;
38862306a36Sopenharmony_ci	case 1:
38962306a36Sopenharmony_ci		_debug("extract UUID");
39062306a36Sopenharmony_ci		ret = afs_extract_data(call, false);
39162306a36Sopenharmony_ci		switch (ret) {
39262306a36Sopenharmony_ci		case 0:		break;
39362306a36Sopenharmony_ci		case -EAGAIN:	return 0;
39462306a36Sopenharmony_ci		default:	return ret;
39562306a36Sopenharmony_ci		}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci		_debug("unmarshall UUID");
39862306a36Sopenharmony_ci		call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL);
39962306a36Sopenharmony_ci		if (!call->request)
40062306a36Sopenharmony_ci			return -ENOMEM;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci		b = call->buffer;
40362306a36Sopenharmony_ci		r = call->request;
40462306a36Sopenharmony_ci		r->time_low			= b[0];
40562306a36Sopenharmony_ci		r->time_mid			= htons(ntohl(b[1]));
40662306a36Sopenharmony_ci		r->time_hi_and_version		= htons(ntohl(b[2]));
40762306a36Sopenharmony_ci		r->clock_seq_hi_and_reserved 	= ntohl(b[3]);
40862306a36Sopenharmony_ci		r->clock_seq_low		= ntohl(b[4]);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		for (loop = 0; loop < 6; loop++)
41162306a36Sopenharmony_ci			r->node[loop] = ntohl(b[loop + 5]);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci		call->unmarshall++;
41462306a36Sopenharmony_ci		fallthrough;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	case 2:
41762306a36Sopenharmony_ci		break;
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
42162306a36Sopenharmony_ci		return afs_io_error(call, afs_io_error_cm_reply);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	/* we'll need the file server record as that tells us which set of
42462306a36Sopenharmony_ci	 * vnodes to operate upon */
42562306a36Sopenharmony_ci	return afs_find_cm_server_by_uuid(call, call->request);
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci/*
42962306a36Sopenharmony_ci * allow the fileserver to see if the cache manager is still alive
43062306a36Sopenharmony_ci */
43162306a36Sopenharmony_cistatic void SRXAFSCB_Probe(struct work_struct *work)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	struct afs_call *call = container_of(work, struct afs_call, work);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	_enter("");
43662306a36Sopenharmony_ci	afs_send_empty_reply(call);
43762306a36Sopenharmony_ci	afs_put_call(call);
43862306a36Sopenharmony_ci	_leave("");
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci/*
44262306a36Sopenharmony_ci * deliver request data to a CB.Probe call
44362306a36Sopenharmony_ci */
44462306a36Sopenharmony_cistatic int afs_deliver_cb_probe(struct afs_call *call)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	int ret;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	_enter("");
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	afs_extract_discard(call, 0);
45162306a36Sopenharmony_ci	ret = afs_extract_data(call, false);
45262306a36Sopenharmony_ci	if (ret < 0)
45362306a36Sopenharmony_ci		return ret;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
45662306a36Sopenharmony_ci		return afs_io_error(call, afs_io_error_cm_reply);
45762306a36Sopenharmony_ci	return afs_find_cm_server_by_peer(call);
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci/*
46162306a36Sopenharmony_ci * Allow the fileserver to quickly find out if the cache manager has been
46262306a36Sopenharmony_ci * rebooted.
46362306a36Sopenharmony_ci */
46462306a36Sopenharmony_cistatic void SRXAFSCB_ProbeUuid(struct work_struct *work)
46562306a36Sopenharmony_ci{
46662306a36Sopenharmony_ci	struct afs_call *call = container_of(work, struct afs_call, work);
46762306a36Sopenharmony_ci	struct afs_uuid *r = call->request;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	_enter("");
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (memcmp(r, &call->net->uuid, sizeof(call->net->uuid)) == 0)
47262306a36Sopenharmony_ci		afs_send_empty_reply(call);
47362306a36Sopenharmony_ci	else
47462306a36Sopenharmony_ci		afs_abort_service_call(call, 1, 1, afs_abort_probeuuid_negative);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	afs_put_call(call);
47762306a36Sopenharmony_ci	_leave("");
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci/*
48162306a36Sopenharmony_ci * deliver request data to a CB.ProbeUuid call
48262306a36Sopenharmony_ci */
48362306a36Sopenharmony_cistatic int afs_deliver_cb_probe_uuid(struct afs_call *call)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	struct afs_uuid *r;
48662306a36Sopenharmony_ci	unsigned loop;
48762306a36Sopenharmony_ci	__be32 *b;
48862306a36Sopenharmony_ci	int ret;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	_enter("{%u}", call->unmarshall);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	switch (call->unmarshall) {
49362306a36Sopenharmony_ci	case 0:
49462306a36Sopenharmony_ci		call->buffer = kmalloc_array(11, sizeof(__be32), GFP_KERNEL);
49562306a36Sopenharmony_ci		if (!call->buffer)
49662306a36Sopenharmony_ci			return -ENOMEM;
49762306a36Sopenharmony_ci		afs_extract_to_buf(call, 11 * sizeof(__be32));
49862306a36Sopenharmony_ci		call->unmarshall++;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci		fallthrough;
50162306a36Sopenharmony_ci	case 1:
50262306a36Sopenharmony_ci		_debug("extract UUID");
50362306a36Sopenharmony_ci		ret = afs_extract_data(call, false);
50462306a36Sopenharmony_ci		switch (ret) {
50562306a36Sopenharmony_ci		case 0:		break;
50662306a36Sopenharmony_ci		case -EAGAIN:	return 0;
50762306a36Sopenharmony_ci		default:	return ret;
50862306a36Sopenharmony_ci		}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci		_debug("unmarshall UUID");
51162306a36Sopenharmony_ci		call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL);
51262306a36Sopenharmony_ci		if (!call->request)
51362306a36Sopenharmony_ci			return -ENOMEM;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci		b = call->buffer;
51662306a36Sopenharmony_ci		r = call->request;
51762306a36Sopenharmony_ci		r->time_low			= b[0];
51862306a36Sopenharmony_ci		r->time_mid			= htons(ntohl(b[1]));
51962306a36Sopenharmony_ci		r->time_hi_and_version		= htons(ntohl(b[2]));
52062306a36Sopenharmony_ci		r->clock_seq_hi_and_reserved 	= ntohl(b[3]);
52162306a36Sopenharmony_ci		r->clock_seq_low		= ntohl(b[4]);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci		for (loop = 0; loop < 6; loop++)
52462306a36Sopenharmony_ci			r->node[loop] = ntohl(b[loop + 5]);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci		call->unmarshall++;
52762306a36Sopenharmony_ci		fallthrough;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	case 2:
53062306a36Sopenharmony_ci		break;
53162306a36Sopenharmony_ci	}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
53462306a36Sopenharmony_ci		return afs_io_error(call, afs_io_error_cm_reply);
53562306a36Sopenharmony_ci	return afs_find_cm_server_by_peer(call);
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci/*
53962306a36Sopenharmony_ci * allow the fileserver to ask about the cache manager's capabilities
54062306a36Sopenharmony_ci */
54162306a36Sopenharmony_cistatic void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	struct afs_call *call = container_of(work, struct afs_call, work);
54462306a36Sopenharmony_ci	int loop;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	struct {
54762306a36Sopenharmony_ci		struct /* InterfaceAddr */ {
54862306a36Sopenharmony_ci			__be32 nifs;
54962306a36Sopenharmony_ci			__be32 uuid[11];
55062306a36Sopenharmony_ci			__be32 ifaddr[32];
55162306a36Sopenharmony_ci			__be32 netmask[32];
55262306a36Sopenharmony_ci			__be32 mtu[32];
55362306a36Sopenharmony_ci		} ia;
55462306a36Sopenharmony_ci		struct /* Capabilities */ {
55562306a36Sopenharmony_ci			__be32 capcount;
55662306a36Sopenharmony_ci			__be32 caps[1];
55762306a36Sopenharmony_ci		} cap;
55862306a36Sopenharmony_ci	} reply;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	_enter("");
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	memset(&reply, 0, sizeof(reply));
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	reply.ia.uuid[0] = call->net->uuid.time_low;
56562306a36Sopenharmony_ci	reply.ia.uuid[1] = htonl(ntohs(call->net->uuid.time_mid));
56662306a36Sopenharmony_ci	reply.ia.uuid[2] = htonl(ntohs(call->net->uuid.time_hi_and_version));
56762306a36Sopenharmony_ci	reply.ia.uuid[3] = htonl((s8) call->net->uuid.clock_seq_hi_and_reserved);
56862306a36Sopenharmony_ci	reply.ia.uuid[4] = htonl((s8) call->net->uuid.clock_seq_low);
56962306a36Sopenharmony_ci	for (loop = 0; loop < 6; loop++)
57062306a36Sopenharmony_ci		reply.ia.uuid[loop + 5] = htonl((s8) call->net->uuid.node[loop]);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	reply.cap.capcount = htonl(1);
57362306a36Sopenharmony_ci	reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION);
57462306a36Sopenharmony_ci	afs_send_simple_reply(call, &reply, sizeof(reply));
57562306a36Sopenharmony_ci	afs_put_call(call);
57662306a36Sopenharmony_ci	_leave("");
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci/*
58062306a36Sopenharmony_ci * deliver request data to a CB.TellMeAboutYourself call
58162306a36Sopenharmony_ci */
58262306a36Sopenharmony_cistatic int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	int ret;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	_enter("");
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	afs_extract_discard(call, 0);
58962306a36Sopenharmony_ci	ret = afs_extract_data(call, false);
59062306a36Sopenharmony_ci	if (ret < 0)
59162306a36Sopenharmony_ci		return ret;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
59462306a36Sopenharmony_ci		return afs_io_error(call, afs_io_error_cm_reply);
59562306a36Sopenharmony_ci	return afs_find_cm_server_by_peer(call);
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci/*
59962306a36Sopenharmony_ci * deliver request data to a YFS CB.CallBack call
60062306a36Sopenharmony_ci */
60162306a36Sopenharmony_cistatic int afs_deliver_yfs_cb_callback(struct afs_call *call)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	struct afs_callback_break *cb;
60462306a36Sopenharmony_ci	struct yfs_xdr_YFSFid *bp;
60562306a36Sopenharmony_ci	size_t size;
60662306a36Sopenharmony_ci	int ret, loop;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	_enter("{%u}", call->unmarshall);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	switch (call->unmarshall) {
61162306a36Sopenharmony_ci	case 0:
61262306a36Sopenharmony_ci		afs_extract_to_tmp(call);
61362306a36Sopenharmony_ci		call->unmarshall++;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci		/* extract the FID array and its count in two steps */
61662306a36Sopenharmony_ci		fallthrough;
61762306a36Sopenharmony_ci	case 1:
61862306a36Sopenharmony_ci		_debug("extract FID count");
61962306a36Sopenharmony_ci		ret = afs_extract_data(call, true);
62062306a36Sopenharmony_ci		if (ret < 0)
62162306a36Sopenharmony_ci			return ret;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci		call->count = ntohl(call->tmp);
62462306a36Sopenharmony_ci		_debug("FID count: %u", call->count);
62562306a36Sopenharmony_ci		if (call->count > YFSCBMAX)
62662306a36Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_cb_fid_count);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci		size = array_size(call->count, sizeof(struct yfs_xdr_YFSFid));
62962306a36Sopenharmony_ci		call->buffer = kmalloc(size, GFP_KERNEL);
63062306a36Sopenharmony_ci		if (!call->buffer)
63162306a36Sopenharmony_ci			return -ENOMEM;
63262306a36Sopenharmony_ci		afs_extract_to_buf(call, size);
63362306a36Sopenharmony_ci		call->unmarshall++;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci		fallthrough;
63662306a36Sopenharmony_ci	case 2:
63762306a36Sopenharmony_ci		_debug("extract FID array");
63862306a36Sopenharmony_ci		ret = afs_extract_data(call, false);
63962306a36Sopenharmony_ci		if (ret < 0)
64062306a36Sopenharmony_ci			return ret;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci		_debug("unmarshall FID array");
64362306a36Sopenharmony_ci		call->request = kcalloc(call->count,
64462306a36Sopenharmony_ci					sizeof(struct afs_callback_break),
64562306a36Sopenharmony_ci					GFP_KERNEL);
64662306a36Sopenharmony_ci		if (!call->request)
64762306a36Sopenharmony_ci			return -ENOMEM;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci		cb = call->request;
65062306a36Sopenharmony_ci		bp = call->buffer;
65162306a36Sopenharmony_ci		for (loop = call->count; loop > 0; loop--, cb++) {
65262306a36Sopenharmony_ci			cb->fid.vid	= xdr_to_u64(bp->volume);
65362306a36Sopenharmony_ci			cb->fid.vnode	= xdr_to_u64(bp->vnode.lo);
65462306a36Sopenharmony_ci			cb->fid.vnode_hi = ntohl(bp->vnode.hi);
65562306a36Sopenharmony_ci			cb->fid.unique	= ntohl(bp->vnode.unique);
65662306a36Sopenharmony_ci			bp++;
65762306a36Sopenharmony_ci		}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci		afs_extract_to_tmp(call);
66062306a36Sopenharmony_ci		call->unmarshall++;
66162306a36Sopenharmony_ci		fallthrough;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	case 3:
66462306a36Sopenharmony_ci		break;
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
66862306a36Sopenharmony_ci		return afs_io_error(call, afs_io_error_cm_reply);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	/* We'll need the file server record as that tells us which set of
67162306a36Sopenharmony_ci	 * vnodes to operate upon.
67262306a36Sopenharmony_ci	 */
67362306a36Sopenharmony_ci	return afs_find_cm_server_by_peer(call);
67462306a36Sopenharmony_ci}
675