aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-10-19 19:57:58 -0400
committerDavid Howells <dhowells@redhat.com>2018-10-23 19:41:08 -0400
commit35dbfba3111a5ef0663bb89185ce8dfdbef63f8d (patch)
tree53d00127f785779f24adca8234f395d9f8a6180f
parent06aeb2971457b33c1123af9f307a55f3dc4052c9 (diff)
afs: Implement the YFS cache manager service
Implement the YFS cache manager service which gives extra capabilities on top of AFS. This is done by listening for an additional service on the same port and indicating that anyone requesting an upgrade should be upgraded to the YFS port. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--fs/afs/cmservice.c103
-rw-r--r--fs/afs/protocol_yfs.h57
-rw-r--r--fs/afs/rxrpc.c15
3 files changed, 174 insertions, 1 deletions
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c
index fc0010d800a0..8cf8d10daa6c 100644
--- a/fs/afs/cmservice.c
+++ b/fs/afs/cmservice.c
@@ -16,6 +16,7 @@
16#include <linux/ip.h> 16#include <linux/ip.h>
17#include "internal.h" 17#include "internal.h"
18#include "afs_cm.h" 18#include "afs_cm.h"
19#include "protocol_yfs.h"
19 20
20static int afs_deliver_cb_init_call_back_state(struct afs_call *); 21static int afs_deliver_cb_init_call_back_state(struct afs_call *);
21static int afs_deliver_cb_init_call_back_state3(struct afs_call *); 22static int afs_deliver_cb_init_call_back_state3(struct afs_call *);
@@ -30,6 +31,8 @@ static void SRXAFSCB_Probe(struct work_struct *);
30static void SRXAFSCB_ProbeUuid(struct work_struct *); 31static void SRXAFSCB_ProbeUuid(struct work_struct *);
31static void SRXAFSCB_TellMeAboutYourself(struct work_struct *); 32static void SRXAFSCB_TellMeAboutYourself(struct work_struct *);
32 33
34static int afs_deliver_yfs_cb_callback(struct afs_call *);
35
33#define CM_NAME(name) \ 36#define CM_NAME(name) \
34 const char afs_SRXCB##name##_name[] __tracepoint_string = \ 37 const char afs_SRXCB##name##_name[] __tracepoint_string = \
35 "CB." #name 38 "CB." #name
@@ -101,12 +104,23 @@ static const struct afs_call_type afs_SRXCBTellMeAboutYourself = {
101}; 104};
102 105
103/* 106/*
107 * YFS CB.CallBack operation type
108 */
109static CM_NAME(YFS_CallBack);
110static const struct afs_call_type afs_SRXYFSCB_CallBack = {
111 .name = afs_SRXCBYFS_CallBack_name,
112 .deliver = afs_deliver_yfs_cb_callback,
113 .destructor = afs_cm_destructor,
114 .work = SRXAFSCB_CallBack,
115};
116
117/*
104 * route an incoming cache manager call 118 * route an incoming cache manager call
105 * - return T if supported, F if not 119 * - return T if supported, F if not
106 */ 120 */
107bool afs_cm_incoming_call(struct afs_call *call) 121bool afs_cm_incoming_call(struct afs_call *call)
108{ 122{
109 _enter("{CB.OP %u}", call->operation_ID); 123 _enter("{%u, CB.OP %u}", call->service_id, call->operation_ID);
110 124
111 switch (call->operation_ID) { 125 switch (call->operation_ID) {
112 case CBCallBack: 126 case CBCallBack:
@@ -127,6 +141,11 @@ bool afs_cm_incoming_call(struct afs_call *call)
127 case CBTellMeAboutYourself: 141 case CBTellMeAboutYourself:
128 call->type = &afs_SRXCBTellMeAboutYourself; 142 call->type = &afs_SRXCBTellMeAboutYourself;
129 return true; 143 return true;
144 case YFSCBCallBack:
145 if (call->service_id != YFS_CM_SERVICE)
146 return false;
147 call->type = &afs_SRXYFSCB_CallBack;
148 return true;
130 default: 149 default:
131 return false; 150 return false;
132 } 151 }
@@ -570,3 +589,85 @@ static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call)
570 589
571 return afs_queue_call_work(call); 590 return afs_queue_call_work(call);
572} 591}
592
593/*
594 * deliver request data to a YFS CB.CallBack call
595 */
596static int afs_deliver_yfs_cb_callback(struct afs_call *call)
597{
598 struct afs_callback_break *cb;
599 struct sockaddr_rxrpc srx;
600 struct yfs_xdr_YFSFid *bp;
601 size_t size;
602 int ret, loop;
603
604 _enter("{%u}", call->unmarshall);
605
606 switch (call->unmarshall) {
607 case 0:
608 afs_extract_to_tmp(call);
609 call->unmarshall++;
610
611 /* extract the FID array and its count in two steps */
612 case 1:
613 _debug("extract FID count");
614 ret = afs_extract_data(call, true);
615 if (ret < 0)
616 return ret;
617
618 call->count = ntohl(call->tmp);
619 _debug("FID count: %u", call->count);
620 if (call->count > YFSCBMAX)
621 return afs_protocol_error(call, -EBADMSG,
622 afs_eproto_cb_fid_count);
623
624 size = array_size(call->count, sizeof(struct yfs_xdr_YFSFid));
625 call->buffer = kmalloc(size, GFP_KERNEL);
626 if (!call->buffer)
627 return -ENOMEM;
628 afs_extract_to_buf(call, size);
629 call->unmarshall++;
630
631 case 2:
632 _debug("extract FID array");
633 ret = afs_extract_data(call, false);
634 if (ret < 0)
635 return ret;
636
637 _debug("unmarshall FID array");
638 call->request = kcalloc(call->count,
639 sizeof(struct afs_callback_break),
640 GFP_KERNEL);
641 if (!call->request)
642 return -ENOMEM;
643
644 cb = call->request;
645 bp = call->buffer;
646 for (loop = call->count; loop > 0; loop--, cb++) {
647 cb->fid.vid = xdr_to_u64(bp->volume);
648 cb->fid.vnode = xdr_to_u64(bp->vnode.lo);
649 cb->fid.vnode_hi = ntohl(bp->vnode.hi);
650 cb->fid.unique = ntohl(bp->vnode.unique);
651 bp++;
652 }
653
654 afs_extract_to_tmp(call);
655 call->unmarshall++;
656
657 case 3:
658 break;
659 }
660
661 if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
662 return afs_io_error(call, afs_io_error_cm_reply);
663
664 /* We'll need the file server record as that tells us which set of
665 * vnodes to operate upon.
666 */
667 rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx);
668 call->cm_server = afs_find_server(call->net, &srx);
669 if (!call->cm_server)
670 trace_afs_cm_no_server(call, &srx);
671
672 return afs_queue_call_work(call);
673}
diff --git a/fs/afs/protocol_yfs.h b/fs/afs/protocol_yfs.h
new file mode 100644
index 000000000000..b7b211dd9857
--- /dev/null
+++ b/fs/afs/protocol_yfs.h
@@ -0,0 +1,57 @@
1/* YFS protocol bits
2 *
3 * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12#define YFS_FS_SERVICE 2500
13#define YFS_CM_SERVICE 2501
14
15#define YFSCBMAX 1024
16
17enum YFS_CM_Operations {
18 YFSCBProbe = 206, /* probe client */
19 YFSCBGetLock = 207, /* get contents of CM lock table */
20 YFSCBXStatsVersion = 209, /* get version of extended statistics */
21 YFSCBGetXStats = 210, /* get contents of extended statistics data */
22 YFSCBInitCallBackState3 = 213, /* initialise callback state, version 3 */
23 YFSCBProbeUuid = 214, /* check the client hasn't rebooted */
24 YFSCBGetServerPrefs = 215,
25 YFSCBGetCellServDV = 216,
26 YFSCBGetLocalCell = 217,
27 YFSCBGetCacheConfig = 218,
28 YFSCBGetCellByNum = 65537,
29 YFSCBTellMeAboutYourself = 65538, /* get client capabilities */
30 YFSCBCallBack = 64204,
31};
32
33struct yfs_xdr_u64 {
34 __be32 msw;
35 __be32 lsw;
36} __packed;
37
38static inline u64 xdr_to_u64(const struct yfs_xdr_u64 x)
39{
40 return ((u64)ntohl(x.msw) << 32) | ntohl(x.lsw);
41}
42
43static inline struct yfs_xdr_u64 u64_to_xdr(const u64 x)
44{
45 return (struct yfs_xdr_u64){ .msw = htonl(x >> 32), .lsw = htonl(x) };
46}
47
48struct yfs_xdr_vnode {
49 struct yfs_xdr_u64 lo;
50 __be32 hi;
51 __be32 unique;
52} __packed;
53
54struct yfs_xdr_YFSFid {
55 struct yfs_xdr_u64 volume;
56 struct yfs_xdr_vnode vnode;
57} __packed;
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index e6ab824ab761..ce98e133caa6 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -16,6 +16,7 @@
16#include <net/af_rxrpc.h> 16#include <net/af_rxrpc.h>
17#include "internal.h" 17#include "internal.h"
18#include "afs_cm.h" 18#include "afs_cm.h"
19#include "protocol_yfs.h"
19 20
20struct workqueue_struct *afs_async_calls; 21struct workqueue_struct *afs_async_calls;
21 22
@@ -42,6 +43,7 @@ int afs_open_socket(struct afs_net *net)
42 struct sockaddr_rxrpc srx; 43 struct sockaddr_rxrpc srx;
43 struct socket *socket; 44 struct socket *socket;
44 unsigned int min_level; 45 unsigned int min_level;
46 u16 service_upgrade[2];
45 int ret; 47 int ret;
46 48
47 _enter(""); 49 _enter("");
@@ -75,6 +77,19 @@ int afs_open_socket(struct afs_net *net)
75 if (ret < 0) 77 if (ret < 0)
76 goto error_2; 78 goto error_2;
77 79
80 srx.srx_service = YFS_CM_SERVICE;
81 ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx));
82 if (ret < 0)
83 goto error_2;
84
85 service_upgrade[0] = CM_SERVICE;
86 service_upgrade[1] = YFS_CM_SERVICE;
87 ret = kernel_setsockopt(socket, SOL_RXRPC, RXRPC_UPGRADEABLE_SERVICE,
88 (void *)service_upgrade, sizeof(service_upgrade));
89 if (ret < 0)
90 goto error_2;
91
92
78 rxrpc_kernel_new_call_notification(socket, afs_rx_new_call, 93 rxrpc_kernel_new_call_notification(socket, afs_rx_new_call,
79 afs_rx_discard_new_call); 94 afs_rx_discard_new_call);
80 95