12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2ec26815aSDavid Howells /* AFS Cache Manager Service
31da177e4SLinus Torvalds *
41da177e4SLinus Torvalds * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
51da177e4SLinus Torvalds * Written by David Howells (dhowells@redhat.com)
61da177e4SLinus Torvalds */
71da177e4SLinus Torvalds
81da177e4SLinus Torvalds #include <linux/module.h>
91da177e4SLinus Torvalds #include <linux/init.h>
105a0e3ad6STejun Heo #include <linux/slab.h>
111da177e4SLinus Torvalds #include <linux/sched.h>
1208e0e7c8SDavid Howells #include <linux/ip.h>
131da177e4SLinus Torvalds #include "internal.h"
1408e0e7c8SDavid Howells #include "afs_cm.h"
1535dbfba3SDavid Howells #include "protocol_yfs.h"
16*57af281eSDavid Howells #define RXRPC_TRACE_ONLY_DEFINE_ENUMS
17*57af281eSDavid Howells #include <trace/events/rxrpc.h>
181da177e4SLinus Torvalds
19d001648eSDavid Howells static int afs_deliver_cb_init_call_back_state(struct afs_call *);
20d001648eSDavid Howells static int afs_deliver_cb_init_call_back_state3(struct afs_call *);
21d001648eSDavid Howells static int afs_deliver_cb_probe(struct afs_call *);
22d001648eSDavid Howells static int afs_deliver_cb_callback(struct afs_call *);
23d001648eSDavid Howells static int afs_deliver_cb_probe_uuid(struct afs_call *);
24d001648eSDavid Howells static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *);
2508e0e7c8SDavid Howells static void afs_cm_destructor(struct afs_call *);
26341f741fSDavid Howells static void SRXAFSCB_CallBack(struct work_struct *);
27341f741fSDavid Howells static void SRXAFSCB_InitCallBackState(struct work_struct *);
28341f741fSDavid Howells static void SRXAFSCB_Probe(struct work_struct *);
29341f741fSDavid Howells static void SRXAFSCB_ProbeUuid(struct work_struct *);
30341f741fSDavid Howells static void SRXAFSCB_TellMeAboutYourself(struct work_struct *);
311da177e4SLinus Torvalds
3235dbfba3SDavid Howells static int afs_deliver_yfs_cb_callback(struct afs_call *);
3335dbfba3SDavid Howells
3408e0e7c8SDavid Howells /*
3508e0e7c8SDavid Howells * CB.CallBack operation type
3608e0e7c8SDavid Howells */
3708e0e7c8SDavid Howells static const struct afs_call_type afs_SRXCBCallBack = {
386c881ca0SDavid Howells .name = "CB.CallBack",
3908e0e7c8SDavid Howells .deliver = afs_deliver_cb_callback,
4008e0e7c8SDavid Howells .destructor = afs_cm_destructor,
41341f741fSDavid Howells .work = SRXAFSCB_CallBack,
421da177e4SLinus Torvalds };
431da177e4SLinus Torvalds
4408e0e7c8SDavid Howells /*
4508e0e7c8SDavid Howells * CB.InitCallBackState operation type
4608e0e7c8SDavid Howells */
4708e0e7c8SDavid Howells static const struct afs_call_type afs_SRXCBInitCallBackState = {
486c881ca0SDavid Howells .name = "CB.InitCallBackState",
4908e0e7c8SDavid Howells .deliver = afs_deliver_cb_init_call_back_state,
5008e0e7c8SDavid Howells .destructor = afs_cm_destructor,
51341f741fSDavid Howells .work = SRXAFSCB_InitCallBackState,
521da177e4SLinus Torvalds };
531da177e4SLinus Torvalds
5408e0e7c8SDavid Howells /*
55c35eccb1SDavid Howells * CB.InitCallBackState3 operation type
56c35eccb1SDavid Howells */
57c35eccb1SDavid Howells static const struct afs_call_type afs_SRXCBInitCallBackState3 = {
586c881ca0SDavid Howells .name = "CB.InitCallBackState3",
59c35eccb1SDavid Howells .deliver = afs_deliver_cb_init_call_back_state3,
60c35eccb1SDavid Howells .destructor = afs_cm_destructor,
61341f741fSDavid Howells .work = SRXAFSCB_InitCallBackState,
62c35eccb1SDavid Howells };
63c35eccb1SDavid Howells
64c35eccb1SDavid Howells /*
6508e0e7c8SDavid Howells * CB.Probe operation type
6608e0e7c8SDavid Howells */
6708e0e7c8SDavid Howells static const struct afs_call_type afs_SRXCBProbe = {
686c881ca0SDavid Howells .name = "CB.Probe",
6908e0e7c8SDavid Howells .deliver = afs_deliver_cb_probe,
7008e0e7c8SDavid Howells .destructor = afs_cm_destructor,
71341f741fSDavid Howells .work = SRXAFSCB_Probe,
7208e0e7c8SDavid Howells };
731da177e4SLinus Torvalds
741da177e4SLinus Torvalds /*
759396d496SDavid Howells * CB.ProbeUuid operation type
769396d496SDavid Howells */
779396d496SDavid Howells static const struct afs_call_type afs_SRXCBProbeUuid = {
786c881ca0SDavid Howells .name = "CB.ProbeUuid",
799396d496SDavid Howells .deliver = afs_deliver_cb_probe_uuid,
809396d496SDavid Howells .destructor = afs_cm_destructor,
81341f741fSDavid Howells .work = SRXAFSCB_ProbeUuid,
829396d496SDavid Howells };
839396d496SDavid Howells
849396d496SDavid Howells /*
857c80bcceSDavid Howells * CB.TellMeAboutYourself operation type
86b908fe6bSDavid Howells */
877c80bcceSDavid Howells static const struct afs_call_type afs_SRXCBTellMeAboutYourself = {
886c881ca0SDavid Howells .name = "CB.TellMeAboutYourself",
897c80bcceSDavid Howells .deliver = afs_deliver_cb_tell_me_about_yourself,
90b908fe6bSDavid Howells .destructor = afs_cm_destructor,
91341f741fSDavid Howells .work = SRXAFSCB_TellMeAboutYourself,
92b908fe6bSDavid Howells };
93b908fe6bSDavid Howells
94b908fe6bSDavid Howells /*
9535dbfba3SDavid Howells * YFS CB.CallBack operation type
9635dbfba3SDavid Howells */
9735dbfba3SDavid Howells static const struct afs_call_type afs_SRXYFSCB_CallBack = {
986c881ca0SDavid Howells .name = "YFSCB.CallBack",
9935dbfba3SDavid Howells .deliver = afs_deliver_yfs_cb_callback,
10035dbfba3SDavid Howells .destructor = afs_cm_destructor,
10135dbfba3SDavid Howells .work = SRXAFSCB_CallBack,
10235dbfba3SDavid Howells };
10335dbfba3SDavid Howells
10435dbfba3SDavid Howells /*
10508e0e7c8SDavid Howells * route an incoming cache manager call
10608e0e7c8SDavid Howells * - return T if supported, F if not
1071da177e4SLinus Torvalds */
afs_cm_incoming_call(struct afs_call * call)10808e0e7c8SDavid Howells bool afs_cm_incoming_call(struct afs_call *call)
1091da177e4SLinus Torvalds {
11035dbfba3SDavid Howells _enter("{%u, CB.OP %u}", call->service_id, call->operation_ID);
1111da177e4SLinus Torvalds
11250a2c953SDavid Howells switch (call->operation_ID) {
11308e0e7c8SDavid Howells case CBCallBack:
11408e0e7c8SDavid Howells call->type = &afs_SRXCBCallBack;
11508e0e7c8SDavid Howells return true;
11608e0e7c8SDavid Howells case CBInitCallBackState:
11708e0e7c8SDavid Howells call->type = &afs_SRXCBInitCallBackState;
11808e0e7c8SDavid Howells return true;
119c35eccb1SDavid Howells case CBInitCallBackState3:
120c35eccb1SDavid Howells call->type = &afs_SRXCBInitCallBackState3;
121c35eccb1SDavid Howells return true;
12208e0e7c8SDavid Howells case CBProbe:
12308e0e7c8SDavid Howells call->type = &afs_SRXCBProbe;
12408e0e7c8SDavid Howells return true;
125f4b3526dSDavid Howells case CBProbeUuid:
126f4b3526dSDavid Howells call->type = &afs_SRXCBProbeUuid;
127f4b3526dSDavid Howells return true;
1287c80bcceSDavid Howells case CBTellMeAboutYourself:
1297c80bcceSDavid Howells call->type = &afs_SRXCBTellMeAboutYourself;
130b908fe6bSDavid Howells return true;
13135dbfba3SDavid Howells case YFSCBCallBack:
13235dbfba3SDavid Howells if (call->service_id != YFS_CM_SERVICE)
13335dbfba3SDavid Howells return false;
13435dbfba3SDavid Howells call->type = &afs_SRXYFSCB_CallBack;
13535dbfba3SDavid Howells return true;
13608e0e7c8SDavid Howells default:
13708e0e7c8SDavid Howells return false;
1381da177e4SLinus Torvalds }
139ec26815aSDavid Howells }
1401da177e4SLinus Torvalds
1411da177e4SLinus Torvalds /*
1423bf0fb6fSDavid Howells * Find the server record by peer address and record a probe to the cache
1433bf0fb6fSDavid Howells * manager from a server.
1443bf0fb6fSDavid Howells */
afs_find_cm_server_by_peer(struct afs_call * call)1453bf0fb6fSDavid Howells static int afs_find_cm_server_by_peer(struct afs_call *call)
1463bf0fb6fSDavid Howells {
1473bf0fb6fSDavid Howells struct sockaddr_rxrpc srx;
1483bf0fb6fSDavid Howells struct afs_server *server;
1493bf0fb6fSDavid Howells
1503bf0fb6fSDavid Howells rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx);
1513bf0fb6fSDavid Howells
1523bf0fb6fSDavid Howells server = afs_find_server(call->net, &srx);
1533bf0fb6fSDavid Howells if (!server) {
1543bf0fb6fSDavid Howells trace_afs_cm_no_server(call, &srx);
1553bf0fb6fSDavid Howells return 0;
1563bf0fb6fSDavid Howells }
1573bf0fb6fSDavid Howells
158ffba718eSDavid Howells call->server = server;
15944746355SDavid Howells return 0;
1603bf0fb6fSDavid Howells }
1613bf0fb6fSDavid Howells
1623bf0fb6fSDavid Howells /*
1633bf0fb6fSDavid Howells * Find the server record by server UUID and record a probe to the cache
1643bf0fb6fSDavid Howells * manager from a server.
1653bf0fb6fSDavid Howells */
afs_find_cm_server_by_uuid(struct afs_call * call,struct afs_uuid * uuid)1663bf0fb6fSDavid Howells static int afs_find_cm_server_by_uuid(struct afs_call *call,
1673bf0fb6fSDavid Howells struct afs_uuid *uuid)
1683bf0fb6fSDavid Howells {
1693bf0fb6fSDavid Howells struct afs_server *server;
1703bf0fb6fSDavid Howells
1713bf0fb6fSDavid Howells rcu_read_lock();
1723bf0fb6fSDavid Howells server = afs_find_server_by_uuid(call->net, call->request);
1733bf0fb6fSDavid Howells rcu_read_unlock();
1743bf0fb6fSDavid Howells if (!server) {
1753bf0fb6fSDavid Howells trace_afs_cm_no_server_u(call, call->request);
1763bf0fb6fSDavid Howells return 0;
1773bf0fb6fSDavid Howells }
1783bf0fb6fSDavid Howells
179ffba718eSDavid Howells call->server = server;
18044746355SDavid Howells return 0;
1813bf0fb6fSDavid Howells }
1823bf0fb6fSDavid Howells
1833bf0fb6fSDavid Howells /*
184428edadeSDavid Howells * Clean up a cache manager call.
1851da177e4SLinus Torvalds */
afs_cm_destructor(struct afs_call * call)18608e0e7c8SDavid Howells static void afs_cm_destructor(struct afs_call *call)
1871da177e4SLinus Torvalds {
18808e0e7c8SDavid Howells kfree(call->buffer);
18908e0e7c8SDavid Howells call->buffer = NULL;
190ec26815aSDavid Howells }
1911da177e4SLinus Torvalds
1921da177e4SLinus Torvalds /*
193dde9f095SDavid Howells * Abort a service call from within an action function.
194dde9f095SDavid Howells */
afs_abort_service_call(struct afs_call * call,u32 abort_code,int error,enum rxrpc_abort_reason why)195dde9f095SDavid Howells static void afs_abort_service_call(struct afs_call *call, u32 abort_code, int error,
196*57af281eSDavid Howells enum rxrpc_abort_reason why)
197dde9f095SDavid Howells {
198dde9f095SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
199dde9f095SDavid Howells abort_code, error, why);
200dde9f095SDavid Howells afs_set_call_complete(call, error, 0);
201dde9f095SDavid Howells }
202dde9f095SDavid Howells
203dde9f095SDavid Howells /*
204c435ee34SDavid Howells * The server supplied a list of callbacks that it wanted to break.
2051da177e4SLinus Torvalds */
SRXAFSCB_CallBack(struct work_struct * work)20608e0e7c8SDavid Howells static void SRXAFSCB_CallBack(struct work_struct *work)
2071da177e4SLinus Torvalds {
20808e0e7c8SDavid Howells struct afs_call *call = container_of(work, struct afs_call, work);
2091da177e4SLinus Torvalds
21008e0e7c8SDavid Howells _enter("");
2111da177e4SLinus Torvalds
212428edadeSDavid Howells /* We need to break the callbacks before sending the reply as the
213428edadeSDavid Howells * server holds up change visibility till it receives our reply so as
214428edadeSDavid Howells * to maintain cache coherency.
215428edadeSDavid Howells */
21645218193SDavid Howells if (call->server) {
2172757a4dcSDavid Howells trace_afs_server(call->server->debug_id,
218c56f9ec8SDavid Howells refcount_read(&call->server->ref),
219977e5f8eSDavid Howells atomic_read(&call->server->active),
22045218193SDavid Howells afs_server_trace_callback);
221ffba718eSDavid Howells afs_break_callbacks(call->server, call->count, call->request);
22245218193SDavid Howells }
223428edadeSDavid Howells
224428edadeSDavid Howells afs_send_empty_reply(call);
225341f741fSDavid Howells afs_put_call(call);
2261da177e4SLinus Torvalds _leave("");
227ec26815aSDavid Howells }
2281da177e4SLinus Torvalds
2291da177e4SLinus Torvalds /*
23008e0e7c8SDavid Howells * deliver request data to a CB.CallBack call
2311da177e4SLinus Torvalds */
afs_deliver_cb_callback(struct afs_call * call)232d001648eSDavid Howells static int afs_deliver_cb_callback(struct afs_call *call)
2331da177e4SLinus Torvalds {
2345cf9dd55SDavid Howells struct afs_callback_break *cb;
23508e0e7c8SDavid Howells __be32 *bp;
23608e0e7c8SDavid Howells int ret, loop;
23708e0e7c8SDavid Howells
238d001648eSDavid Howells _enter("{%u}", call->unmarshall);
23908e0e7c8SDavid Howells
24008e0e7c8SDavid Howells switch (call->unmarshall) {
24108e0e7c8SDavid Howells case 0:
24212bdcf33SDavid Howells afs_extract_to_tmp(call);
24308e0e7c8SDavid Howells call->unmarshall++;
24408e0e7c8SDavid Howells
24508e0e7c8SDavid Howells /* extract the FID array and its count in two steps */
246df561f66SGustavo A. R. Silva fallthrough;
24708e0e7c8SDavid Howells case 1:
24808e0e7c8SDavid Howells _debug("extract FID count");
24912bdcf33SDavid Howells ret = afs_extract_data(call, true);
250372ee163SDavid Howells if (ret < 0)
251372ee163SDavid Howells return ret;
2521da177e4SLinus Torvalds
25308e0e7c8SDavid Howells call->count = ntohl(call->tmp);
25408e0e7c8SDavid Howells _debug("FID count: %u", call->count);
25508e0e7c8SDavid Howells if (call->count > AFSCBMAX)
2567126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_cb_fid_count);
2571da177e4SLinus Torvalds
2586da2ec56SKees Cook call->buffer = kmalloc(array3_size(call->count, 3, 4),
2596da2ec56SKees Cook GFP_KERNEL);
26008e0e7c8SDavid Howells if (!call->buffer)
26108e0e7c8SDavid Howells return -ENOMEM;
26212bdcf33SDavid Howells afs_extract_to_buf(call, call->count * 3 * 4);
26308e0e7c8SDavid Howells call->unmarshall++;
2641da177e4SLinus Torvalds
265df561f66SGustavo A. R. Silva fallthrough;
26608e0e7c8SDavid Howells case 2:
26708e0e7c8SDavid Howells _debug("extract FID array");
26812bdcf33SDavid Howells ret = afs_extract_data(call, true);
269372ee163SDavid Howells if (ret < 0)
270372ee163SDavid Howells return ret;
2711da177e4SLinus Torvalds
27208e0e7c8SDavid Howells _debug("unmarshall FID array");
27308e0e7c8SDavid Howells call->request = kcalloc(call->count,
2745cf9dd55SDavid Howells sizeof(struct afs_callback_break),
27508e0e7c8SDavid Howells GFP_KERNEL);
27608e0e7c8SDavid Howells if (!call->request)
27708e0e7c8SDavid Howells return -ENOMEM;
2781da177e4SLinus Torvalds
27908e0e7c8SDavid Howells cb = call->request;
28008e0e7c8SDavid Howells bp = call->buffer;
28108e0e7c8SDavid Howells for (loop = call->count; loop > 0; loop--, cb++) {
28208e0e7c8SDavid Howells cb->fid.vid = ntohl(*bp++);
28308e0e7c8SDavid Howells cb->fid.vnode = ntohl(*bp++);
28408e0e7c8SDavid Howells cb->fid.unique = ntohl(*bp++);
28508e0e7c8SDavid Howells }
28608e0e7c8SDavid Howells
28712bdcf33SDavid Howells afs_extract_to_tmp(call);
28808e0e7c8SDavid Howells call->unmarshall++;
28908e0e7c8SDavid Howells
29008e0e7c8SDavid Howells /* extract the callback array and its count in two steps */
291df561f66SGustavo A. R. Silva fallthrough;
29208e0e7c8SDavid Howells case 3:
29308e0e7c8SDavid Howells _debug("extract CB count");
29412bdcf33SDavid Howells ret = afs_extract_data(call, true);
295372ee163SDavid Howells if (ret < 0)
296372ee163SDavid Howells return ret;
29708e0e7c8SDavid Howells
298bcd89270SMarc Dionne call->count2 = ntohl(call->tmp);
299bcd89270SMarc Dionne _debug("CB count: %u", call->count2);
300bcd89270SMarc Dionne if (call->count2 != call->count && call->count2 != 0)
3017126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_cb_count);
302fc276122SDavid Howells call->iter = &call->def_iter;
303de4eda9dSAl Viro iov_iter_discard(&call->def_iter, ITER_DEST, call->count2 * 3 * 4);
30408e0e7c8SDavid Howells call->unmarshall++;
30508e0e7c8SDavid Howells
306df561f66SGustavo A. R. Silva fallthrough;
30708e0e7c8SDavid Howells case 4:
30806aeb297SDavid Howells _debug("extract discard %zu/%u",
309fc276122SDavid Howells iov_iter_count(call->iter), call->count2 * 3 * 4);
31006aeb297SDavid Howells
31112bdcf33SDavid Howells ret = afs_extract_data(call, false);
312372ee163SDavid Howells if (ret < 0)
313372ee163SDavid Howells return ret;
31408e0e7c8SDavid Howells
31508e0e7c8SDavid Howells call->unmarshall++;
316b2db6c35SGustavo A. R. Silva fallthrough;
317b2db6c35SGustavo A. R. Silva
318d001648eSDavid Howells case 5:
31908e0e7c8SDavid Howells break;
32008e0e7c8SDavid Howells }
32108e0e7c8SDavid Howells
32298bf40cdSDavid Howells if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
323f51375cdSDavid Howells return afs_io_error(call, afs_io_error_cm_reply);
3241da177e4SLinus Torvalds
32508e0e7c8SDavid Howells /* we'll need the file server record as that tells us which set of
32608e0e7c8SDavid Howells * vnodes to operate upon */
3273bf0fb6fSDavid Howells return afs_find_cm_server_by_peer(call);
328ec26815aSDavid Howells }
3291da177e4SLinus Torvalds
3301da177e4SLinus Torvalds /*
33108e0e7c8SDavid Howells * allow the fileserver to request callback state (re-)initialisation
3321da177e4SLinus Torvalds */
SRXAFSCB_InitCallBackState(struct work_struct * work)33308e0e7c8SDavid Howells static void SRXAFSCB_InitCallBackState(struct work_struct *work)
3341da177e4SLinus Torvalds {
33508e0e7c8SDavid Howells struct afs_call *call = container_of(work, struct afs_call, work);
3361da177e4SLinus Torvalds
337ffba718eSDavid Howells _enter("{%p}", call->server);
3381da177e4SLinus Torvalds
339ffba718eSDavid Howells if (call->server)
340ffba718eSDavid Howells afs_init_callback_state(call->server);
34108e0e7c8SDavid Howells afs_send_empty_reply(call);
342341f741fSDavid Howells afs_put_call(call);
34308e0e7c8SDavid Howells _leave("");
344ec26815aSDavid Howells }
3451da177e4SLinus Torvalds
3461da177e4SLinus Torvalds /*
34708e0e7c8SDavid Howells * deliver request data to a CB.InitCallBackState call
3481da177e4SLinus Torvalds */
afs_deliver_cb_init_call_back_state(struct afs_call * call)349d001648eSDavid Howells static int afs_deliver_cb_init_call_back_state(struct afs_call *call)
3501da177e4SLinus Torvalds {
351372ee163SDavid Howells int ret;
3521da177e4SLinus Torvalds
353d001648eSDavid Howells _enter("");
3541da177e4SLinus Torvalds
35512bdcf33SDavid Howells afs_extract_discard(call, 0);
35612bdcf33SDavid Howells ret = afs_extract_data(call, false);
357372ee163SDavid Howells if (ret < 0)
358372ee163SDavid Howells return ret;
3591da177e4SLinus Torvalds
36008e0e7c8SDavid Howells /* we'll need the file server record as that tells us which set of
36108e0e7c8SDavid Howells * vnodes to operate upon */
3623bf0fb6fSDavid Howells return afs_find_cm_server_by_peer(call);
363ec26815aSDavid Howells }
3641da177e4SLinus Torvalds
3651da177e4SLinus Torvalds /*
366c35eccb1SDavid Howells * deliver request data to a CB.InitCallBackState3 call
367c35eccb1SDavid Howells */
afs_deliver_cb_init_call_back_state3(struct afs_call * call)368d001648eSDavid Howells static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
369c35eccb1SDavid Howells {
37041bb26f8SChristoph Hellwig struct afs_uuid *r;
371d001648eSDavid Howells unsigned loop;
372d001648eSDavid Howells __be32 *b;
373d001648eSDavid Howells int ret;
374c35eccb1SDavid Howells
375d001648eSDavid Howells _enter("");
376c35eccb1SDavid Howells
377d001648eSDavid Howells _enter("{%u}", call->unmarshall);
378d001648eSDavid Howells
379d001648eSDavid Howells switch (call->unmarshall) {
380d001648eSDavid Howells case 0:
3816da2ec56SKees Cook call->buffer = kmalloc_array(11, sizeof(__be32), GFP_KERNEL);
382d001648eSDavid Howells if (!call->buffer)
383d001648eSDavid Howells return -ENOMEM;
38412bdcf33SDavid Howells afs_extract_to_buf(call, 11 * sizeof(__be32));
385d001648eSDavid Howells call->unmarshall++;
386d001648eSDavid Howells
387df561f66SGustavo A. R. Silva fallthrough;
388d001648eSDavid Howells case 1:
389d001648eSDavid Howells _debug("extract UUID");
39012bdcf33SDavid Howells ret = afs_extract_data(call, false);
391d001648eSDavid Howells switch (ret) {
392d001648eSDavid Howells case 0: break;
393d001648eSDavid Howells case -EAGAIN: return 0;
394d001648eSDavid Howells default: return ret;
395d001648eSDavid Howells }
396d001648eSDavid Howells
397d001648eSDavid Howells _debug("unmarshall UUID");
39841bb26f8SChristoph Hellwig call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL);
399d001648eSDavid Howells if (!call->request)
400d001648eSDavid Howells return -ENOMEM;
401d001648eSDavid Howells
402d001648eSDavid Howells b = call->buffer;
403d001648eSDavid Howells r = call->request;
404ff548773SDavid Howells r->time_low = b[0];
405ff548773SDavid Howells r->time_mid = htons(ntohl(b[1]));
406ff548773SDavid Howells r->time_hi_and_version = htons(ntohl(b[2]));
407d001648eSDavid Howells r->clock_seq_hi_and_reserved = ntohl(b[3]);
408d001648eSDavid Howells r->clock_seq_low = ntohl(b[4]);
409d001648eSDavid Howells
410d001648eSDavid Howells for (loop = 0; loop < 6; loop++)
411d001648eSDavid Howells r->node[loop] = ntohl(b[loop + 5]);
412d001648eSDavid Howells
413d001648eSDavid Howells call->unmarshall++;
414b2db6c35SGustavo A. R. Silva fallthrough;
415d001648eSDavid Howells
416d001648eSDavid Howells case 2:
417d001648eSDavid Howells break;
418d001648eSDavid Howells }
419c35eccb1SDavid Howells
42098bf40cdSDavid Howells if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
421f51375cdSDavid Howells return afs_io_error(call, afs_io_error_cm_reply);
422c35eccb1SDavid Howells
423c35eccb1SDavid Howells /* we'll need the file server record as that tells us which set of
424c35eccb1SDavid Howells * vnodes to operate upon */
4253bf0fb6fSDavid Howells return afs_find_cm_server_by_uuid(call, call->request);
426c35eccb1SDavid Howells }
427c35eccb1SDavid Howells
428c35eccb1SDavid Howells /*
42908e0e7c8SDavid Howells * allow the fileserver to see if the cache manager is still alive
4301da177e4SLinus Torvalds */
SRXAFSCB_Probe(struct work_struct * work)43108e0e7c8SDavid Howells static void SRXAFSCB_Probe(struct work_struct *work)
4321da177e4SLinus Torvalds {
43308e0e7c8SDavid Howells struct afs_call *call = container_of(work, struct afs_call, work);
4341da177e4SLinus Torvalds
43508e0e7c8SDavid Howells _enter("");
43608e0e7c8SDavid Howells afs_send_empty_reply(call);
437341f741fSDavid Howells afs_put_call(call);
43808e0e7c8SDavid Howells _leave("");
439ec26815aSDavid Howells }
4401da177e4SLinus Torvalds
4411da177e4SLinus Torvalds /*
44208e0e7c8SDavid Howells * deliver request data to a CB.Probe call
4431da177e4SLinus Torvalds */
afs_deliver_cb_probe(struct afs_call * call)444d001648eSDavid Howells static int afs_deliver_cb_probe(struct afs_call *call)
4451da177e4SLinus Torvalds {
446372ee163SDavid Howells int ret;
447372ee163SDavid Howells
448d001648eSDavid Howells _enter("");
4491da177e4SLinus Torvalds
45012bdcf33SDavid Howells afs_extract_discard(call, 0);
45112bdcf33SDavid Howells ret = afs_extract_data(call, false);
452372ee163SDavid Howells if (ret < 0)
453372ee163SDavid Howells return ret;
4541da177e4SLinus Torvalds
45598bf40cdSDavid Howells if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
456f51375cdSDavid Howells return afs_io_error(call, afs_io_error_cm_reply);
4573bf0fb6fSDavid Howells return afs_find_cm_server_by_peer(call);
458ec26815aSDavid Howells }
459b908fe6bSDavid Howells
460b908fe6bSDavid Howells /*
4613120c170SDavid Howells * Allow the fileserver to quickly find out if the cache manager has been
4623120c170SDavid Howells * rebooted.
4639396d496SDavid Howells */
SRXAFSCB_ProbeUuid(struct work_struct * work)4649396d496SDavid Howells static void SRXAFSCB_ProbeUuid(struct work_struct *work)
4659396d496SDavid Howells {
4669396d496SDavid Howells struct afs_call *call = container_of(work, struct afs_call, work);
46741bb26f8SChristoph Hellwig struct afs_uuid *r = call->request;
4689396d496SDavid Howells
4699396d496SDavid Howells _enter("");
4709396d496SDavid Howells
471f044c884SDavid Howells if (memcmp(r, &call->net->uuid, sizeof(call->net->uuid)) == 0)
4722067b2b3SDavid Howells afs_send_empty_reply(call);
4739396d496SDavid Howells else
474*57af281eSDavid Howells afs_abort_service_call(call, 1, 1, afs_abort_probeuuid_negative);
4759396d496SDavid Howells
476341f741fSDavid Howells afs_put_call(call);
4779396d496SDavid Howells _leave("");
4789396d496SDavid Howells }
4799396d496SDavid Howells
4809396d496SDavid Howells /*
4819396d496SDavid Howells * deliver request data to a CB.ProbeUuid call
4829396d496SDavid Howells */
afs_deliver_cb_probe_uuid(struct afs_call * call)483d001648eSDavid Howells static int afs_deliver_cb_probe_uuid(struct afs_call *call)
4849396d496SDavid Howells {
48541bb26f8SChristoph Hellwig struct afs_uuid *r;
4869396d496SDavid Howells unsigned loop;
4879396d496SDavid Howells __be32 *b;
4889396d496SDavid Howells int ret;
4899396d496SDavid Howells
490d001648eSDavid Howells _enter("{%u}", call->unmarshall);
4919396d496SDavid Howells
4929396d496SDavid Howells switch (call->unmarshall) {
4939396d496SDavid Howells case 0:
4946da2ec56SKees Cook call->buffer = kmalloc_array(11, sizeof(__be32), GFP_KERNEL);
4959396d496SDavid Howells if (!call->buffer)
4969396d496SDavid Howells return -ENOMEM;
49712bdcf33SDavid Howells afs_extract_to_buf(call, 11 * sizeof(__be32));
4989396d496SDavid Howells call->unmarshall++;
4999396d496SDavid Howells
500df561f66SGustavo A. R. Silva fallthrough;
5019396d496SDavid Howells case 1:
5029396d496SDavid Howells _debug("extract UUID");
50312bdcf33SDavid Howells ret = afs_extract_data(call, false);
5049396d496SDavid Howells switch (ret) {
5059396d496SDavid Howells case 0: break;
5069396d496SDavid Howells case -EAGAIN: return 0;
5079396d496SDavid Howells default: return ret;
5089396d496SDavid Howells }
5099396d496SDavid Howells
5109396d496SDavid Howells _debug("unmarshall UUID");
51141bb26f8SChristoph Hellwig call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL);
5129396d496SDavid Howells if (!call->request)
5139396d496SDavid Howells return -ENOMEM;
5149396d496SDavid Howells
5159396d496SDavid Howells b = call->buffer;
5169396d496SDavid Howells r = call->request;
517fe342cf7SDavid Howells r->time_low = b[0];
518fe342cf7SDavid Howells r->time_mid = htons(ntohl(b[1]));
519fe342cf7SDavid Howells r->time_hi_and_version = htons(ntohl(b[2]));
5209396d496SDavid Howells r->clock_seq_hi_and_reserved = ntohl(b[3]);
5219396d496SDavid Howells r->clock_seq_low = ntohl(b[4]);
5229396d496SDavid Howells
5239396d496SDavid Howells for (loop = 0; loop < 6; loop++)
5249396d496SDavid Howells r->node[loop] = ntohl(b[loop + 5]);
5259396d496SDavid Howells
5269396d496SDavid Howells call->unmarshall++;
527b2db6c35SGustavo A. R. Silva fallthrough;
5289396d496SDavid Howells
5299396d496SDavid Howells case 2:
5309396d496SDavid Howells break;
5319396d496SDavid Howells }
5329396d496SDavid Howells
53398bf40cdSDavid Howells if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
534f51375cdSDavid Howells return afs_io_error(call, afs_io_error_cm_reply);
5353120c170SDavid Howells return afs_find_cm_server_by_peer(call);
5369396d496SDavid Howells }
5379396d496SDavid Howells
5389396d496SDavid Howells /*
539b908fe6bSDavid Howells * allow the fileserver to ask about the cache manager's capabilities
540b908fe6bSDavid Howells */
SRXAFSCB_TellMeAboutYourself(struct work_struct * work)5417c80bcceSDavid Howells static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
542b908fe6bSDavid Howells {
543b908fe6bSDavid Howells struct afs_call *call = container_of(work, struct afs_call, work);
54435ebfc22SFlorian Westphal int loop;
545b908fe6bSDavid Howells
546b908fe6bSDavid Howells struct {
547b908fe6bSDavid Howells struct /* InterfaceAddr */ {
548b908fe6bSDavid Howells __be32 nifs;
549b908fe6bSDavid Howells __be32 uuid[11];
550b908fe6bSDavid Howells __be32 ifaddr[32];
551b908fe6bSDavid Howells __be32 netmask[32];
552b908fe6bSDavid Howells __be32 mtu[32];
553b908fe6bSDavid Howells } ia;
554b908fe6bSDavid Howells struct /* Capabilities */ {
555b908fe6bSDavid Howells __be32 capcount;
556b908fe6bSDavid Howells __be32 caps[1];
557b908fe6bSDavid Howells } cap;
558b908fe6bSDavid Howells } reply;
559b908fe6bSDavid Howells
560b908fe6bSDavid Howells _enter("");
561b908fe6bSDavid Howells
562b908fe6bSDavid Howells memset(&reply, 0, sizeof(reply));
563b908fe6bSDavid Howells
564f044c884SDavid Howells reply.ia.uuid[0] = call->net->uuid.time_low;
565f044c884SDavid Howells reply.ia.uuid[1] = htonl(ntohs(call->net->uuid.time_mid));
566f044c884SDavid Howells reply.ia.uuid[2] = htonl(ntohs(call->net->uuid.time_hi_and_version));
567f044c884SDavid Howells reply.ia.uuid[3] = htonl((s8) call->net->uuid.clock_seq_hi_and_reserved);
568f044c884SDavid Howells reply.ia.uuid[4] = htonl((s8) call->net->uuid.clock_seq_low);
569b908fe6bSDavid Howells for (loop = 0; loop < 6; loop++)
570f044c884SDavid Howells reply.ia.uuid[loop + 5] = htonl((s8) call->net->uuid.node[loop]);
571b908fe6bSDavid Howells
572b908fe6bSDavid Howells reply.cap.capcount = htonl(1);
573b908fe6bSDavid Howells reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION);
574b908fe6bSDavid Howells afs_send_simple_reply(call, &reply, sizeof(reply));
575341f741fSDavid Howells afs_put_call(call);
576b908fe6bSDavid Howells _leave("");
577b908fe6bSDavid Howells }
578b908fe6bSDavid Howells
579b908fe6bSDavid Howells /*
5807c80bcceSDavid Howells * deliver request data to a CB.TellMeAboutYourself call
581b908fe6bSDavid Howells */
afs_deliver_cb_tell_me_about_yourself(struct afs_call * call)582d001648eSDavid Howells static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call)
583b908fe6bSDavid Howells {
584372ee163SDavid Howells int ret;
585372ee163SDavid Howells
586d001648eSDavid Howells _enter("");
587b908fe6bSDavid Howells
58812bdcf33SDavid Howells afs_extract_discard(call, 0);
58912bdcf33SDavid Howells ret = afs_extract_data(call, false);
590372ee163SDavid Howells if (ret < 0)
591372ee163SDavid Howells return ret;
592b908fe6bSDavid Howells
59398bf40cdSDavid Howells if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
594f51375cdSDavid Howells return afs_io_error(call, afs_io_error_cm_reply);
5953bf0fb6fSDavid Howells return afs_find_cm_server_by_peer(call);
596b908fe6bSDavid Howells }
59735dbfba3SDavid Howells
59835dbfba3SDavid Howells /*
59935dbfba3SDavid Howells * deliver request data to a YFS CB.CallBack call
60035dbfba3SDavid Howells */
afs_deliver_yfs_cb_callback(struct afs_call * call)60135dbfba3SDavid Howells static int afs_deliver_yfs_cb_callback(struct afs_call *call)
60235dbfba3SDavid Howells {
60335dbfba3SDavid Howells struct afs_callback_break *cb;
60435dbfba3SDavid Howells struct yfs_xdr_YFSFid *bp;
60535dbfba3SDavid Howells size_t size;
60635dbfba3SDavid Howells int ret, loop;
60735dbfba3SDavid Howells
60835dbfba3SDavid Howells _enter("{%u}", call->unmarshall);
60935dbfba3SDavid Howells
61035dbfba3SDavid Howells switch (call->unmarshall) {
61135dbfba3SDavid Howells case 0:
61235dbfba3SDavid Howells afs_extract_to_tmp(call);
61335dbfba3SDavid Howells call->unmarshall++;
61435dbfba3SDavid Howells
61535dbfba3SDavid Howells /* extract the FID array and its count in two steps */
616df561f66SGustavo A. R. Silva fallthrough;
61735dbfba3SDavid Howells case 1:
61835dbfba3SDavid Howells _debug("extract FID count");
61935dbfba3SDavid Howells ret = afs_extract_data(call, true);
62035dbfba3SDavid Howells if (ret < 0)
62135dbfba3SDavid Howells return ret;
62235dbfba3SDavid Howells
62335dbfba3SDavid Howells call->count = ntohl(call->tmp);
62435dbfba3SDavid Howells _debug("FID count: %u", call->count);
62535dbfba3SDavid Howells if (call->count > YFSCBMAX)
6267126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_cb_fid_count);
62735dbfba3SDavid Howells
62835dbfba3SDavid Howells size = array_size(call->count, sizeof(struct yfs_xdr_YFSFid));
62935dbfba3SDavid Howells call->buffer = kmalloc(size, GFP_KERNEL);
63035dbfba3SDavid Howells if (!call->buffer)
63135dbfba3SDavid Howells return -ENOMEM;
63235dbfba3SDavid Howells afs_extract_to_buf(call, size);
63335dbfba3SDavid Howells call->unmarshall++;
63435dbfba3SDavid Howells
635df561f66SGustavo A. R. Silva fallthrough;
63635dbfba3SDavid Howells case 2:
63735dbfba3SDavid Howells _debug("extract FID array");
63835dbfba3SDavid Howells ret = afs_extract_data(call, false);
63935dbfba3SDavid Howells if (ret < 0)
64035dbfba3SDavid Howells return ret;
64135dbfba3SDavid Howells
64235dbfba3SDavid Howells _debug("unmarshall FID array");
64335dbfba3SDavid Howells call->request = kcalloc(call->count,
64435dbfba3SDavid Howells sizeof(struct afs_callback_break),
64535dbfba3SDavid Howells GFP_KERNEL);
64635dbfba3SDavid Howells if (!call->request)
64735dbfba3SDavid Howells return -ENOMEM;
64835dbfba3SDavid Howells
64935dbfba3SDavid Howells cb = call->request;
65035dbfba3SDavid Howells bp = call->buffer;
65135dbfba3SDavid Howells for (loop = call->count; loop > 0; loop--, cb++) {
65235dbfba3SDavid Howells cb->fid.vid = xdr_to_u64(bp->volume);
65335dbfba3SDavid Howells cb->fid.vnode = xdr_to_u64(bp->vnode.lo);
65435dbfba3SDavid Howells cb->fid.vnode_hi = ntohl(bp->vnode.hi);
65535dbfba3SDavid Howells cb->fid.unique = ntohl(bp->vnode.unique);
65635dbfba3SDavid Howells bp++;
65735dbfba3SDavid Howells }
65835dbfba3SDavid Howells
65935dbfba3SDavid Howells afs_extract_to_tmp(call);
66035dbfba3SDavid Howells call->unmarshall++;
661b2db6c35SGustavo A. R. Silva fallthrough;
66235dbfba3SDavid Howells
66335dbfba3SDavid Howells case 3:
66435dbfba3SDavid Howells break;
66535dbfba3SDavid Howells }
66635dbfba3SDavid Howells
66735dbfba3SDavid Howells if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
66835dbfba3SDavid Howells return afs_io_error(call, afs_io_error_cm_reply);
66935dbfba3SDavid Howells
67035dbfba3SDavid Howells /* We'll need the file server record as that tells us which set of
67135dbfba3SDavid Howells * vnodes to operate upon.
67235dbfba3SDavid Howells */
6733bf0fb6fSDavid Howells return afs_find_cm_server_by_peer(call);
67435dbfba3SDavid Howells }
675