linux/fs/afs/cmservice.c
<<
>>
Prefs
   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
  20struct workqueue_struct *afs_cm_workqueue;
  21#endif  /*  0  */
  22
  23static int afs_deliver_cb_init_call_back_state(struct afs_call *,
  24                                               struct sk_buff *, bool);
  25static int afs_deliver_cb_init_call_back_state3(struct afs_call *,
  26                                                struct sk_buff *, bool);
  27static int afs_deliver_cb_probe(struct afs_call *, struct sk_buff *, bool);
  28static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool);
  29static int afs_deliver_cb_probe_uuid(struct afs_call *, struct sk_buff *, bool);
  30static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *,
  31                                                 struct sk_buff *, bool);
  32static void afs_cm_destructor(struct afs_call *);
  33
  34/*
  35 * CB.CallBack operation type
  36 */
  37static const struct afs_call_type afs_SRXCBCallBack = {
  38        .name           = "CB.CallBack",
  39        .deliver        = afs_deliver_cb_callback,
  40        .abort_to_error = afs_abort_to_error,
  41        .destructor     = afs_cm_destructor,
  42};
  43
  44/*
  45 * CB.InitCallBackState operation type
  46 */
  47static const struct afs_call_type afs_SRXCBInitCallBackState = {
  48        .name           = "CB.InitCallBackState",
  49        .deliver        = afs_deliver_cb_init_call_back_state,
  50        .abort_to_error = afs_abort_to_error,
  51        .destructor     = afs_cm_destructor,
  52};
  53
  54/*
  55 * CB.InitCallBackState3 operation type
  56 */
  57static const struct afs_call_type afs_SRXCBInitCallBackState3 = {
  58        .name           = "CB.InitCallBackState3",
  59        .deliver        = afs_deliver_cb_init_call_back_state3,
  60        .abort_to_error = afs_abort_to_error,
  61        .destructor     = afs_cm_destructor,
  62};
  63
  64/*
  65 * CB.Probe operation type
  66 */
  67static const struct afs_call_type afs_SRXCBProbe = {
  68        .name           = "CB.Probe",
  69        .deliver        = afs_deliver_cb_probe,
  70        .abort_to_error = afs_abort_to_error,
  71        .destructor     = afs_cm_destructor,
  72};
  73
  74/*
  75 * CB.ProbeUuid operation type
  76 */
  77static const struct afs_call_type afs_SRXCBProbeUuid = {
  78        .name           = "CB.ProbeUuid",
  79        .deliver        = afs_deliver_cb_probe_uuid,
  80        .abort_to_error = afs_abort_to_error,
  81        .destructor     = afs_cm_destructor,
  82};
  83
  84/*
  85 * CB.TellMeAboutYourself operation type
  86 */
  87static const struct afs_call_type afs_SRXCBTellMeAboutYourself = {
  88        .name           = "CB.TellMeAboutYourself",
  89        .deliver        = afs_deliver_cb_tell_me_about_yourself,
  90        .abort_to_error = afs_abort_to_error,
  91        .destructor     = afs_cm_destructor,
  92};
  93
  94/*
  95 * route an incoming cache manager call
  96 * - return T if supported, F if not
  97 */
  98bool afs_cm_incoming_call(struct afs_call *call)
  99{
 100        u32 operation_id = ntohl(call->operation_ID);
 101
 102        _enter("{CB.OP %u}", operation_id);
 103
 104        switch (operation_id) {
 105        case CBCallBack:
 106                call->type = &afs_SRXCBCallBack;
 107                return true;
 108        case CBInitCallBackState:
 109                call->type = &afs_SRXCBInitCallBackState;
 110                return true;
 111        case CBInitCallBackState3:
 112                call->type = &afs_SRXCBInitCallBackState3;
 113                return true;
 114        case CBProbe:
 115                call->type = &afs_SRXCBProbe;
 116                return true;
 117        case CBTellMeAboutYourself:
 118                call->type = &afs_SRXCBTellMeAboutYourself;
 119                return true;
 120        default:
 121                return false;
 122        }
 123}
 124
 125/*
 126 * clean up a cache manager call
 127 */
 128static void afs_cm_destructor(struct afs_call *call)
 129{
 130        _enter("");
 131
 132        afs_put_server(call->server);
 133        call->server = NULL;
 134        kfree(call->buffer);
 135        call->buffer = NULL;
 136}
 137
 138/*
 139 * allow the fileserver to see if the cache manager is still alive
 140 */
 141static void SRXAFSCB_CallBack(struct work_struct *work)
 142{
 143        struct afs_call *call = container_of(work, struct afs_call, work);
 144
 145        _enter("");
 146
 147        /* be sure to send the reply *before* attempting to spam the AFS server
 148         * with FSFetchStatus requests on the vnodes with broken callbacks lest
 149         * the AFS server get into a vicious cycle of trying to break further
 150         * callbacks because it hadn't received completion of the CBCallBack op
 151         * yet */
 152        afs_send_empty_reply(call);
 153
 154        afs_break_callbacks(call->server, call->count, call->request);
 155        _leave("");
 156}
 157
 158/*
 159 * deliver request data to a CB.CallBack call
 160 */
 161static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
 162                                   bool last)
 163{
 164        struct afs_callback *cb;
 165        struct afs_server *server;
 166        struct in_addr addr;
 167        __be32 *bp;
 168        u32 tmp;
 169        int ret, loop;
 170
 171        _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
 172
 173        switch (call->unmarshall) {
 174        case 0:
 175                call->offset = 0;
 176                call->unmarshall++;
 177
 178                /* extract the FID array and its count in two steps */
 179        case 1:
 180                _debug("extract FID count");
 181                ret = afs_extract_data(call, skb, last, &call->tmp, 4);
 182                switch (ret) {
 183                case 0:         break;
 184                case -EAGAIN:   return 0;
 185                default:        return ret;
 186                }
 187
 188                call->count = ntohl(call->tmp);
 189                _debug("FID count: %u", call->count);
 190                if (call->count > AFSCBMAX)
 191                        return -EBADMSG;
 192
 193                call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL);
 194                if (!call->buffer)
 195                        return -ENOMEM;
 196                call->offset = 0;
 197                call->unmarshall++;
 198
 199        case 2:
 200                _debug("extract FID array");
 201                ret = afs_extract_data(call, skb, last, call->buffer,
 202                                       call->count * 3 * 4);
 203                switch (ret) {
 204                case 0:         break;
 205                case -EAGAIN:   return 0;
 206                default:        return ret;
 207                }
 208
 209                _debug("unmarshall FID array");
 210                call->request = kcalloc(call->count,
 211                                        sizeof(struct afs_callback),
 212                                        GFP_KERNEL);
 213                if (!call->request)
 214                        return -ENOMEM;
 215
 216                cb = call->request;
 217                bp = call->buffer;
 218                for (loop = call->count; loop > 0; loop--, cb++) {
 219                        cb->fid.vid     = ntohl(*bp++);
 220                        cb->fid.vnode   = ntohl(*bp++);
 221                        cb->fid.unique  = ntohl(*bp++);
 222                        cb->type        = AFSCM_CB_UNTYPED;
 223                }
 224
 225                call->offset = 0;
 226                call->unmarshall++;
 227
 228                /* extract the callback array and its count in two steps */
 229        case 3:
 230                _debug("extract CB count");
 231                ret = afs_extract_data(call, skb, last, &call->tmp, 4);
 232                switch (ret) {
 233                case 0:         break;
 234                case -EAGAIN:   return 0;
 235                default:        return ret;
 236                }
 237
 238                tmp = ntohl(call->tmp);
 239                _debug("CB count: %u", tmp);
 240                if (tmp != call->count && tmp != 0)
 241                        return -EBADMSG;
 242                call->offset = 0;
 243                call->unmarshall++;
 244                if (tmp == 0)
 245                        goto empty_cb_array;
 246
 247        case 4:
 248                _debug("extract CB array");
 249                ret = afs_extract_data(call, skb, last, call->request,
 250                                       call->count * 3 * 4);
 251                switch (ret) {
 252                case 0:         break;
 253                case -EAGAIN:   return 0;
 254                default:        return ret;
 255                }
 256
 257                _debug("unmarshall CB array");
 258                cb = call->request;
 259                bp = call->buffer;
 260                for (loop = call->count; loop > 0; loop--, cb++) {
 261                        cb->version     = ntohl(*bp++);
 262                        cb->expiry      = ntohl(*bp++);
 263                        cb->type        = ntohl(*bp++);
 264                }
 265
 266        empty_cb_array:
 267                call->offset = 0;
 268                call->unmarshall++;
 269
 270        case 5:
 271                _debug("trailer");
 272                if (skb->len != 0)
 273                        return -EBADMSG;
 274                break;
 275        }
 276
 277        if (!last)
 278                return 0;
 279
 280        call->state = AFS_CALL_REPLYING;
 281
 282        /* we'll need the file server record as that tells us which set of
 283         * vnodes to operate upon */
 284        memcpy(&addr, &ip_hdr(skb)->saddr, 4);
 285        server = afs_find_server(&addr);
 286        if (!server)
 287                return -ENOTCONN;
 288        call->server = server;
 289
 290        INIT_WORK(&call->work, SRXAFSCB_CallBack);
 291        schedule_work(&call->work);
 292        return 0;
 293}
 294
 295/*
 296 * allow the fileserver to request callback state (re-)initialisation
 297 */
 298static void SRXAFSCB_InitCallBackState(struct work_struct *work)
 299{
 300        struct afs_call *call = container_of(work, struct afs_call, work);
 301
 302        _enter("{%p}", call->server);
 303
 304        afs_init_callback_state(call->server);
 305        afs_send_empty_reply(call);
 306        _leave("");
 307}
 308
 309/*
 310 * deliver request data to a CB.InitCallBackState call
 311 */
 312static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
 313                                               struct sk_buff *skb,
 314                                               bool last)
 315{
 316        struct afs_server *server;
 317        struct in_addr addr;
 318
 319        _enter(",{%u},%d", skb->len, last);
 320
 321        if (skb->len > 0)
 322                return -EBADMSG;
 323        if (!last)
 324                return 0;
 325
 326        /* no unmarshalling required */
 327        call->state = AFS_CALL_REPLYING;
 328
 329        /* we'll need the file server record as that tells us which set of
 330         * vnodes to operate upon */
 331        memcpy(&addr, &ip_hdr(skb)->saddr, 4);
 332        server = afs_find_server(&addr);
 333        if (!server)
 334                return -ENOTCONN;
 335        call->server = server;
 336
 337        INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
 338        schedule_work(&call->work);
 339        return 0;
 340}
 341
 342/*
 343 * deliver request data to a CB.InitCallBackState3 call
 344 */
 345static int afs_deliver_cb_init_call_back_state3(struct afs_call *call,
 346                                                struct sk_buff *skb,
 347                                                bool last)
 348{
 349        struct afs_server *server;
 350        struct in_addr addr;
 351
 352        _enter(",{%u},%d", skb->len, last);
 353
 354        if (!last)
 355                return 0;
 356
 357        /* no unmarshalling required */
 358        call->state = AFS_CALL_REPLYING;
 359
 360        /* we'll need the file server record as that tells us which set of
 361         * vnodes to operate upon */
 362        memcpy(&addr, &ip_hdr(skb)->saddr, 4);
 363        server = afs_find_server(&addr);
 364        if (!server)
 365                return -ENOTCONN;
 366        call->server = server;
 367
 368        INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
 369        schedule_work(&call->work);
 370        return 0;
 371}
 372
 373/*
 374 * allow the fileserver to see if the cache manager is still alive
 375 */
 376static void SRXAFSCB_Probe(struct work_struct *work)
 377{
 378        struct afs_call *call = container_of(work, struct afs_call, work);
 379
 380        _enter("");
 381        afs_send_empty_reply(call);
 382        _leave("");
 383}
 384
 385/*
 386 * deliver request data to a CB.Probe call
 387 */
 388static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
 389                                bool last)
 390{
 391        _enter(",{%u},%d", skb->len, last);
 392
 393        if (skb->len > 0)
 394                return -EBADMSG;
 395        if (!last)
 396                return 0;
 397
 398        /* no unmarshalling required */
 399        call->state = AFS_CALL_REPLYING;
 400
 401        INIT_WORK(&call->work, SRXAFSCB_Probe);
 402        schedule_work(&call->work);
 403        return 0;
 404}
 405
 406/*
 407 * allow the fileserver to quickly find out if the fileserver has been rebooted
 408 */
 409static void SRXAFSCB_ProbeUuid(struct work_struct *work)
 410{
 411        struct afs_call *call = container_of(work, struct afs_call, work);
 412        struct afs_uuid *r = call->request;
 413
 414        struct {
 415                __be32  match;
 416        } reply;
 417
 418        _enter("");
 419
 420
 421        if (memcmp(r, &afs_uuid, sizeof(afs_uuid)) == 0)
 422                reply.match = htonl(0);
 423        else
 424                reply.match = htonl(1);
 425
 426        afs_send_simple_reply(call, &reply, sizeof(reply));
 427        _leave("");
 428}
 429
 430/*
 431 * deliver request data to a CB.ProbeUuid call
 432 */
 433static int afs_deliver_cb_probe_uuid(struct afs_call *call, struct sk_buff *skb,
 434                                     bool last)
 435{
 436        struct afs_uuid *r;
 437        unsigned loop;
 438        __be32 *b;
 439        int ret;
 440
 441        _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
 442
 443        if (skb->len > 0)
 444                return -EBADMSG;
 445        if (!last)
 446                return 0;
 447
 448        switch (call->unmarshall) {
 449        case 0:
 450                call->offset = 0;
 451                call->buffer = kmalloc(11 * sizeof(__be32), GFP_KERNEL);
 452                if (!call->buffer)
 453                        return -ENOMEM;
 454                call->unmarshall++;
 455
 456        case 1:
 457                _debug("extract UUID");
 458                ret = afs_extract_data(call, skb, last, call->buffer,
 459                                       11 * sizeof(__be32));
 460                switch (ret) {
 461                case 0:         break;
 462                case -EAGAIN:   return 0;
 463                default:        return ret;
 464                }
 465
 466                _debug("unmarshall UUID");
 467                call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL);
 468                if (!call->request)
 469                        return -ENOMEM;
 470
 471                b = call->buffer;
 472                r = call->request;
 473                r->time_low                     = ntohl(b[0]);
 474                r->time_mid                     = ntohl(b[1]);
 475                r->time_hi_and_version          = ntohl(b[2]);
 476                r->clock_seq_hi_and_reserved    = ntohl(b[3]);
 477                r->clock_seq_low                = ntohl(b[4]);
 478
 479                for (loop = 0; loop < 6; loop++)
 480                        r->node[loop] = ntohl(b[loop + 5]);
 481
 482                call->offset = 0;
 483                call->unmarshall++;
 484
 485        case 2:
 486                _debug("trailer");
 487                if (skb->len != 0)
 488                        return -EBADMSG;
 489                break;
 490        }
 491
 492        if (!last)
 493                return 0;
 494
 495        call->state = AFS_CALL_REPLYING;
 496
 497        INIT_WORK(&call->work, SRXAFSCB_ProbeUuid);
 498        schedule_work(&call->work);
 499        return 0;
 500}
 501
 502/*
 503 * allow the fileserver to ask about the cache manager's capabilities
 504 */
 505static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
 506{
 507        struct afs_interface *ifs;
 508        struct afs_call *call = container_of(work, struct afs_call, work);
 509        int loop, nifs;
 510
 511        struct {
 512                struct /* InterfaceAddr */ {
 513                        __be32 nifs;
 514                        __be32 uuid[11];
 515                        __be32 ifaddr[32];
 516                        __be32 netmask[32];
 517                        __be32 mtu[32];
 518                } ia;
 519                struct /* Capabilities */ {
 520                        __be32 capcount;
 521                        __be32 caps[1];
 522                } cap;
 523        } reply;
 524
 525        _enter("");
 526
 527        nifs = 0;
 528        ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL);
 529        if (ifs) {
 530                nifs = afs_get_ipv4_interfaces(ifs, 32, false);
 531                if (nifs < 0) {
 532                        kfree(ifs);
 533                        ifs = NULL;
 534                        nifs = 0;
 535                }
 536        }
 537
 538        memset(&reply, 0, sizeof(reply));
 539        reply.ia.nifs = htonl(nifs);
 540
 541        reply.ia.uuid[0] = htonl(afs_uuid.time_low);
 542        reply.ia.uuid[1] = htonl(afs_uuid.time_mid);
 543        reply.ia.uuid[2] = htonl(afs_uuid.time_hi_and_version);
 544        reply.ia.uuid[3] = htonl((s8) afs_uuid.clock_seq_hi_and_reserved);
 545        reply.ia.uuid[4] = htonl((s8) afs_uuid.clock_seq_low);
 546        for (loop = 0; loop < 6; loop++)
 547                reply.ia.uuid[loop + 5] = htonl((s8) afs_uuid.node[loop]);
 548
 549        if (ifs) {
 550                for (loop = 0; loop < nifs; loop++) {
 551                        reply.ia.ifaddr[loop] = ifs[loop].address.s_addr;
 552                        reply.ia.netmask[loop] = ifs[loop].netmask.s_addr;
 553                        reply.ia.mtu[loop] = htonl(ifs[loop].mtu);
 554                }
 555                kfree(ifs);
 556        }
 557
 558        reply.cap.capcount = htonl(1);
 559        reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION);
 560        afs_send_simple_reply(call, &reply, sizeof(reply));
 561
 562        _leave("");
 563}
 564
 565/*
 566 * deliver request data to a CB.TellMeAboutYourself call
 567 */
 568static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call,
 569                                                 struct sk_buff *skb, bool last)
 570{
 571        _enter(",{%u},%d", skb->len, last);
 572
 573        if (skb->len > 0)
 574                return -EBADMSG;
 575        if (!last)
 576                return 0;
 577
 578        /* no unmarshalling required */
 579        call->state = AFS_CALL_REPLYING;
 580
 581        INIT_WORK(&call->work, SRXAFSCB_TellMeAboutYourself);
 582        schedule_work(&call->work);
 583        return 0;
 584}
 585
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.