1 /* AFS Cache Manager Service 2 * 3 * Copyright (C) 2002 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 License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12 #include <linux/module.h> 13 #include <linux/init.h> 14 #include <linux/sched.h> 15 #include <linux/ip.h> 16 #include "internal.h" 17 #include "afs_cm.h" 18 19 #if 0 20 struct workqueue_struct *afs_cm_workqueue; 21 #endif /* 0 */ 22 23 static int afs_deliver_cb_init_call_back_state(struct afs_call *, 24 struct sk_buff *, bool); 25 static int afs_deliver_cb_init_call_back_state3(struct afs_call *, 26 struct sk_buff *, bool); 27 static int afs_deliver_cb_probe(struct afs_call *, struct sk_buff *, bool); 28 static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool); 29 static int afs_deliver_cb_get_capabilities(struct afs_call *, struct sk_buff *, 30 bool); 31 static void afs_cm_destructor(struct afs_call *); 32 33 /* 34 * CB.CallBack operation type 35 */ 36 static const struct afs_call_type afs_SRXCBCallBack = { 37 .name = "CB.CallBack", 38 .deliver = afs_deliver_cb_callback, 39 .abort_to_error = afs_abort_to_error, 40 .destructor = afs_cm_destructor, 41 }; 42 43 /* 44 * CB.InitCallBackState operation type 45 */ 46 static const struct afs_call_type afs_SRXCBInitCallBackState = { 47 .name = "CB.InitCallBackState", 48 .deliver = afs_deliver_cb_init_call_back_state, 49 .abort_to_error = afs_abort_to_error, 50 .destructor = afs_cm_destructor, 51 }; 52 53 /* 54 * CB.InitCallBackState3 operation type 55 */ 56 static const struct afs_call_type afs_SRXCBInitCallBackState3 = { 57 .name = "CB.InitCallBackState3", 58 .deliver = afs_deliver_cb_init_call_back_state3, 59 .abort_to_error = afs_abort_to_error, 60 .destructor = afs_cm_destructor, 61 }; 62 63 /* 64 * CB.Probe operation type 65 */ 66 static const struct afs_call_type afs_SRXCBProbe = { 67 .name = "CB.Probe", 68 .deliver = afs_deliver_cb_probe, 69 .abort_to_error = afs_abort_to_error, 70 .destructor = afs_cm_destructor, 71 }; 72 73 /* 74 * CB.GetCapabilities operation type 75 */ 76 static const struct afs_call_type afs_SRXCBGetCapabilites = { 77 .name = "CB.GetCapabilities", 78 .deliver = afs_deliver_cb_get_capabilities, 79 .abort_to_error = afs_abort_to_error, 80 .destructor = afs_cm_destructor, 81 }; 82 83 /* 84 * route an incoming cache manager call 85 * - return T if supported, F if not 86 */ 87 bool afs_cm_incoming_call(struct afs_call *call) 88 { 89 u32 operation_id = ntohl(call->operation_ID); 90 91 _enter("{CB.OP %u}", operation_id); 92 93 switch (operation_id) { 94 case CBCallBack: 95 call->type = &afs_SRXCBCallBack; 96 return true; 97 case CBInitCallBackState: 98 call->type = &afs_SRXCBInitCallBackState; 99 return true; 100 case CBInitCallBackState3: 101 call->type = &afs_SRXCBInitCallBackState3; 102 return true; 103 case CBProbe: 104 call->type = &afs_SRXCBProbe; 105 return true; 106 case CBGetCapabilities: 107 call->type = &afs_SRXCBGetCapabilites; 108 return true; 109 default: 110 return false; 111 } 112 } 113 114 /* 115 * clean up a cache manager call 116 */ 117 static void afs_cm_destructor(struct afs_call *call) 118 { 119 _enter(""); 120 121 afs_put_server(call->server); 122 call->server = NULL; 123 kfree(call->buffer); 124 call->buffer = NULL; 125 } 126 127 /* 128 * allow the fileserver to see if the cache manager is still alive 129 */ 130 static void SRXAFSCB_CallBack(struct work_struct *work) 131 { 132 struct afs_call *call = container_of(work, struct afs_call, work); 133 134 _enter(""); 135 136 /* be sure to send the reply *before* attempting to spam the AFS server 137 * with FSFetchStatus requests on the vnodes with broken callbacks lest 138 * the AFS server get into a vicious cycle of trying to break further 139 * callbacks because it hadn't received completion of the CBCallBack op 140 * yet */ 141 afs_send_empty_reply(call); 142 143 afs_break_callbacks(call->server, call->count, call->request); 144 _leave(""); 145 } 146 147 /* 148 * deliver request data to a CB.CallBack call 149 */ 150 static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb, 151 bool last) 152 { 153 struct afs_callback *cb; 154 struct afs_server *server; 155 struct in_addr addr; 156 __be32 *bp; 157 u32 tmp; 158 int ret, loop; 159 160 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 161 162 switch (call->unmarshall) { 163 case 0: 164 call->offset = 0; 165 call->unmarshall++; 166 167 /* extract the FID array and its count in two steps */ 168 case 1: 169 _debug("extract FID count"); 170 ret = afs_extract_data(call, skb, last, &call->tmp, 4); 171 switch (ret) { 172 case 0: break; 173 case -EAGAIN: return 0; 174 default: return ret; 175 } 176 177 call->count = ntohl(call->tmp); 178 _debug("FID count: %u", call->count); 179 if (call->count > AFSCBMAX) 180 return -EBADMSG; 181 182 call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL); 183 if (!call->buffer) 184 return -ENOMEM; 185 call->offset = 0; 186 call->unmarshall++; 187 188 case 2: 189 _debug("extract FID array"); 190 ret = afs_extract_data(call, skb, last, call->buffer, 191 call->count * 3 * 4); 192 switch (ret) { 193 case 0: break; 194 case -EAGAIN: return 0; 195 default: return ret; 196 } 197 198 _debug("unmarshall FID array"); 199 call->request = kcalloc(call->count, 200 sizeof(struct afs_callback), 201 GFP_KERNEL); 202 if (!call->request) 203 return -ENOMEM; 204 205 cb = call->request; 206 bp = call->buffer; 207 for (loop = call->count; loop > 0; loop--, cb++) { 208 cb->fid.vid = ntohl(*bp++); 209 cb->fid.vnode = ntohl(*bp++); 210 cb->fid.unique = ntohl(*bp++); 211 cb->type = AFSCM_CB_UNTYPED; 212 } 213 214 call->offset = 0; 215 call->unmarshall++; 216 217 /* extract the callback array and its count in two steps */ 218 case 3: 219 _debug("extract CB count"); 220 ret = afs_extract_data(call, skb, last, &call->tmp, 4); 221 switch (ret) { 222 case 0: break; 223 case -EAGAIN: return 0; 224 default: return ret; 225 } 226 227 tmp = ntohl(call->tmp); 228 _debug("CB count: %u", tmp); 229 if (tmp != call->count && tmp != 0) 230 return -EBADMSG; 231 call->offset = 0; 232 call->unmarshall++; 233 if (tmp == 0) 234 goto empty_cb_array; 235 236 case 4: 237 _debug("extract CB array"); 238 ret = afs_extract_data(call, skb, last, call->request, 239 call->count * 3 * 4); 240 switch (ret) { 241 case 0: break; 242 case -EAGAIN: return 0; 243 default: return ret; 244 } 245 246 _debug("unmarshall CB array"); 247 cb = call->request; 248 bp = call->buffer; 249 for (loop = call->count; loop > 0; loop--, cb++) { 250 cb->version = ntohl(*bp++); 251 cb->expiry = ntohl(*bp++); 252 cb->type = ntohl(*bp++); 253 } 254 255 empty_cb_array: 256 call->offset = 0; 257 call->unmarshall++; 258 259 case 5: 260 _debug("trailer"); 261 if (skb->len != 0) 262 return -EBADMSG; 263 break; 264 } 265 266 if (!last) 267 return 0; 268 269 call->state = AFS_CALL_REPLYING; 270 271 /* we'll need the file server record as that tells us which set of 272 * vnodes to operate upon */ 273 memcpy(&addr, &ip_hdr(skb)->saddr, 4); 274 server = afs_find_server(&addr); 275 if (!server) 276 return -ENOTCONN; 277 call->server = server; 278 279 INIT_WORK(&call->work, SRXAFSCB_CallBack); 280 schedule_work(&call->work); 281 return 0; 282 } 283 284 /* 285 * allow the fileserver to request callback state (re-)initialisation 286 */ 287 static void SRXAFSCB_InitCallBackState(struct work_struct *work) 288 { 289 struct afs_call *call = container_of(work, struct afs_call, work); 290 291 _enter("{%p}", call->server); 292 293 afs_init_callback_state(call->server); 294 afs_send_empty_reply(call); 295 _leave(""); 296 } 297 298 /* 299 * deliver request data to a CB.InitCallBackState call 300 */ 301 static int afs_deliver_cb_init_call_back_state(struct afs_call *call, 302 struct sk_buff *skb, 303 bool last) 304 { 305 struct afs_server *server; 306 struct in_addr addr; 307 308 _enter(",{%u},%d", skb->len, last); 309 310 if (skb->len > 0) 311 return -EBADMSG; 312 if (!last) 313 return 0; 314 315 /* no unmarshalling required */ 316 call->state = AFS_CALL_REPLYING; 317 318 /* we'll need the file server record as that tells us which set of 319 * vnodes to operate upon */ 320 memcpy(&addr, &ip_hdr(skb)->saddr, 4); 321 server = afs_find_server(&addr); 322 if (!server) 323 return -ENOTCONN; 324 call->server = server; 325 326 INIT_WORK(&call->work, SRXAFSCB_InitCallBackState); 327 schedule_work(&call->work); 328 return 0; 329 } 330 331 /* 332 * deliver request data to a CB.InitCallBackState3 call 333 */ 334 static int afs_deliver_cb_init_call_back_state3(struct afs_call *call, 335 struct sk_buff *skb, 336 bool last) 337 { 338 struct afs_server *server; 339 struct in_addr addr; 340 341 _enter(",{%u},%d", skb->len, last); 342 343 if (!last) 344 return 0; 345 346 /* no unmarshalling required */ 347 call->state = AFS_CALL_REPLYING; 348 349 /* we'll need the file server record as that tells us which set of 350 * vnodes to operate upon */ 351 memcpy(&addr, &ip_hdr(skb)->saddr, 4); 352 server = afs_find_server(&addr); 353 if (!server) 354 return -ENOTCONN; 355 call->server = server; 356 357 INIT_WORK(&call->work, SRXAFSCB_InitCallBackState); 358 schedule_work(&call->work); 359 return 0; 360 } 361 362 /* 363 * allow the fileserver to see if the cache manager is still alive 364 */ 365 static void SRXAFSCB_Probe(struct work_struct *work) 366 { 367 struct afs_call *call = container_of(work, struct afs_call, work); 368 369 _enter(""); 370 afs_send_empty_reply(call); 371 _leave(""); 372 } 373 374 /* 375 * deliver request data to a CB.Probe call 376 */ 377 static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb, 378 bool last) 379 { 380 _enter(",{%u},%d", skb->len, last); 381 382 if (skb->len > 0) 383 return -EBADMSG; 384 if (!last) 385 return 0; 386 387 /* no unmarshalling required */ 388 call->state = AFS_CALL_REPLYING; 389 390 INIT_WORK(&call->work, SRXAFSCB_Probe); 391 schedule_work(&call->work); 392 return 0; 393 } 394 395 /* 396 * allow the fileserver to ask about the cache manager's capabilities 397 */ 398 static void SRXAFSCB_GetCapabilities(struct work_struct *work) 399 { 400 struct afs_interface *ifs; 401 struct afs_call *call = container_of(work, struct afs_call, work); 402 int loop, nifs; 403 404 struct { 405 struct /* InterfaceAddr */ { 406 __be32 nifs; 407 __be32 uuid[11]; 408 __be32 ifaddr[32]; 409 __be32 netmask[32]; 410 __be32 mtu[32]; 411 } ia; 412 struct /* Capabilities */ { 413 __be32 capcount; 414 __be32 caps[1]; 415 } cap; 416 } reply; 417 418 _enter(""); 419 420 nifs = 0; 421 ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL); 422 if (ifs) { 423 nifs = afs_get_ipv4_interfaces(ifs, 32, false); 424 if (nifs < 0) { 425 kfree(ifs); 426 ifs = NULL; 427 nifs = 0; 428 } 429 } 430 431 memset(&reply, 0, sizeof(reply)); 432 reply.ia.nifs = htonl(nifs); 433 434 reply.ia.uuid[0] = htonl(afs_uuid.time_low); 435 reply.ia.uuid[1] = htonl(afs_uuid.time_mid); 436 reply.ia.uuid[2] = htonl(afs_uuid.time_hi_and_version); 437 reply.ia.uuid[3] = htonl((s8) afs_uuid.clock_seq_hi_and_reserved); 438 reply.ia.uuid[4] = htonl((s8) afs_uuid.clock_seq_low); 439 for (loop = 0; loop < 6; loop++) 440 reply.ia.uuid[loop + 5] = htonl((s8) afs_uuid.node[loop]); 441 442 if (ifs) { 443 for (loop = 0; loop < nifs; loop++) { 444 reply.ia.ifaddr[loop] = ifs[loop].address.s_addr; 445 reply.ia.netmask[loop] = ifs[loop].netmask.s_addr; 446 reply.ia.mtu[loop] = htonl(ifs[loop].mtu); 447 } 448 kfree(ifs); 449 } 450 451 reply.cap.capcount = htonl(1); 452 reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION); 453 afs_send_simple_reply(call, &reply, sizeof(reply)); 454 455 _leave(""); 456 } 457 458 /* 459 * deliver request data to a CB.GetCapabilities call 460 */ 461 static int afs_deliver_cb_get_capabilities(struct afs_call *call, 462 struct sk_buff *skb, bool last) 463 { 464 _enter(",{%u},%d", skb->len, last); 465 466 if (skb->len > 0) 467 return -EBADMSG; 468 if (!last) 469 return 0; 470 471 /* no unmarshalling required */ 472 call->state = AFS_CALL_REPLYING; 473 474 INIT_WORK(&call->work, SRXAFSCB_GetCapabilities); 475 schedule_work(&call->work); 476 return 0; 477 } 478