Merge commit 'v2.6.30' into for-2.6.31
[safe/jmp/linux-2.6] / fs / afs / cmservice.c
index c714117..eb76548 100644 (file)
 #include "internal.h"
 #include "afs_cm.h"
 
+#if 0
 struct workqueue_struct *afs_cm_workqueue;
+#endif  /*  0  */
 
 static int afs_deliver_cb_init_call_back_state(struct afs_call *,
                                               struct sk_buff *, bool);
+static int afs_deliver_cb_init_call_back_state3(struct afs_call *,
+                                               struct sk_buff *, bool);
 static int afs_deliver_cb_probe(struct afs_call *, struct sk_buff *, bool);
 static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool);
+static int afs_deliver_cb_probe_uuid(struct afs_call *, struct sk_buff *, bool);
+static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *,
+                                                struct sk_buff *, bool);
 static void afs_cm_destructor(struct afs_call *);
 
 /*
  * CB.CallBack operation type
  */
 static const struct afs_call_type afs_SRXCBCallBack = {
+       .name           = "CB.CallBack",
        .deliver        = afs_deliver_cb_callback,
        .abort_to_error = afs_abort_to_error,
        .destructor     = afs_cm_destructor,
@@ -37,21 +45,53 @@ static const struct afs_call_type afs_SRXCBCallBack = {
  * CB.InitCallBackState operation type
  */
 static const struct afs_call_type afs_SRXCBInitCallBackState = {
+       .name           = "CB.InitCallBackState",
        .deliver        = afs_deliver_cb_init_call_back_state,
        .abort_to_error = afs_abort_to_error,
        .destructor     = afs_cm_destructor,
 };
 
 /*
+ * CB.InitCallBackState3 operation type
+ */
+static const struct afs_call_type afs_SRXCBInitCallBackState3 = {
+       .name           = "CB.InitCallBackState3",
+       .deliver        = afs_deliver_cb_init_call_back_state3,
+       .abort_to_error = afs_abort_to_error,
+       .destructor     = afs_cm_destructor,
+};
+
+/*
  * CB.Probe operation type
  */
 static const struct afs_call_type afs_SRXCBProbe = {
+       .name           = "CB.Probe",
        .deliver        = afs_deliver_cb_probe,
        .abort_to_error = afs_abort_to_error,
        .destructor     = afs_cm_destructor,
 };
 
 /*
+ * CB.ProbeUuid operation type
+ */
+static const struct afs_call_type afs_SRXCBProbeUuid = {
+       .name           = "CB.ProbeUuid",
+       .deliver        = afs_deliver_cb_probe_uuid,
+       .abort_to_error = afs_abort_to_error,
+       .destructor     = afs_cm_destructor,
+};
+
+/*
+ * CB.TellMeAboutYourself operation type
+ */
+static const struct afs_call_type afs_SRXCBTellMeAboutYourself = {
+       .name           = "CB.TellMeAboutYourself",
+       .deliver        = afs_deliver_cb_tell_me_about_yourself,
+       .abort_to_error = afs_abort_to_error,
+       .destructor     = afs_cm_destructor,
+};
+
+/*
  * route an incoming cache manager call
  * - return T if supported, F if not
  */
@@ -68,9 +108,15 @@ bool afs_cm_incoming_call(struct afs_call *call)
        case CBInitCallBackState:
                call->type = &afs_SRXCBInitCallBackState;
                return true;
+       case CBInitCallBackState3:
+               call->type = &afs_SRXCBInitCallBackState3;
+               return true;
        case CBProbe:
                call->type = &afs_SRXCBProbe;
                return true;
+       case CBTellMeAboutYourself:
+               call->type = &afs_SRXCBTellMeAboutYourself;
+               return true;
        default:
                return false;
        }
@@ -294,6 +340,37 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
 }
 
 /*
+ * deliver request data to a CB.InitCallBackState3 call
+ */
+static int afs_deliver_cb_init_call_back_state3(struct afs_call *call,
+                                               struct sk_buff *skb,
+                                               bool last)
+{
+       struct afs_server *server;
+       struct in_addr addr;
+
+       _enter(",{%u},%d", skb->len, last);
+
+       if (!last)
+               return 0;
+
+       /* no unmarshalling required */
+       call->state = AFS_CALL_REPLYING;
+
+       /* we'll need the file server record as that tells us which set of
+        * vnodes to operate upon */
+       memcpy(&addr, &ip_hdr(skb)->saddr, 4);
+       server = afs_find_server(&addr);
+       if (!server)
+               return -ENOTCONN;
+       call->server = server;
+
+       INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
+       schedule_work(&call->work);
+       return 0;
+}
+
+/*
  * allow the fileserver to see if the cache manager is still alive
  */
 static void SRXAFSCB_Probe(struct work_struct *work)
@@ -325,3 +402,183 @@ static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
        schedule_work(&call->work);
        return 0;
 }
+
+/*
+ * allow the fileserver to quickly find out if the fileserver has been rebooted
+ */
+static void SRXAFSCB_ProbeUuid(struct work_struct *work)
+{
+       struct afs_call *call = container_of(work, struct afs_call, work);
+       struct afs_uuid *r = call->request;
+
+       struct {
+               __be32  match;
+       } reply;
+
+       _enter("");
+
+
+       if (memcmp(r, &afs_uuid, sizeof(afs_uuid)) == 0)
+               reply.match = htonl(0);
+       else
+               reply.match = htonl(1);
+
+       afs_send_simple_reply(call, &reply, sizeof(reply));
+       _leave("");
+}
+
+/*
+ * deliver request data to a CB.ProbeUuid call
+ */
+static int afs_deliver_cb_probe_uuid(struct afs_call *call, struct sk_buff *skb,
+                                    bool last)
+{
+       struct afs_uuid *r;
+       unsigned loop;
+       __be32 *b;
+       int ret;
+
+       _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
+
+       if (skb->len > 0)
+               return -EBADMSG;
+       if (!last)
+               return 0;
+
+       switch (call->unmarshall) {
+       case 0:
+               call->offset = 0;
+               call->buffer = kmalloc(11 * sizeof(__be32), GFP_KERNEL);
+               if (!call->buffer)
+                       return -ENOMEM;
+               call->unmarshall++;
+
+       case 1:
+               _debug("extract UUID");
+               ret = afs_extract_data(call, skb, last, call->buffer,
+                                      11 * sizeof(__be32));
+               switch (ret) {
+               case 0:         break;
+               case -EAGAIN:   return 0;
+               default:        return ret;
+               }
+
+               _debug("unmarshall UUID");
+               call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL);
+               if (!call->request)
+                       return -ENOMEM;
+
+               b = call->buffer;
+               r = call->request;
+               r->time_low                     = ntohl(b[0]);
+               r->time_mid                     = ntohl(b[1]);
+               r->time_hi_and_version          = ntohl(b[2]);
+               r->clock_seq_hi_and_reserved    = ntohl(b[3]);
+               r->clock_seq_low                = ntohl(b[4]);
+
+               for (loop = 0; loop < 6; loop++)
+                       r->node[loop] = ntohl(b[loop + 5]);
+
+               call->offset = 0;
+               call->unmarshall++;
+
+       case 2:
+               _debug("trailer");
+               if (skb->len != 0)
+                       return -EBADMSG;
+               break;
+       }
+
+       if (!last)
+               return 0;
+
+       call->state = AFS_CALL_REPLYING;
+
+       INIT_WORK(&call->work, SRXAFSCB_ProbeUuid);
+       schedule_work(&call->work);
+       return 0;
+}
+
+/*
+ * allow the fileserver to ask about the cache manager's capabilities
+ */
+static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
+{
+       struct afs_interface *ifs;
+       struct afs_call *call = container_of(work, struct afs_call, work);
+       int loop, nifs;
+
+       struct {
+               struct /* InterfaceAddr */ {
+                       __be32 nifs;
+                       __be32 uuid[11];
+                       __be32 ifaddr[32];
+                       __be32 netmask[32];
+                       __be32 mtu[32];
+               } ia;
+               struct /* Capabilities */ {
+                       __be32 capcount;
+                       __be32 caps[1];
+               } cap;
+       } reply;
+
+       _enter("");
+
+       nifs = 0;
+       ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL);
+       if (ifs) {
+               nifs = afs_get_ipv4_interfaces(ifs, 32, false);
+               if (nifs < 0) {
+                       kfree(ifs);
+                       ifs = NULL;
+                       nifs = 0;
+               }
+       }
+
+       memset(&reply, 0, sizeof(reply));
+       reply.ia.nifs = htonl(nifs);
+
+       reply.ia.uuid[0] = htonl(afs_uuid.time_low);
+       reply.ia.uuid[1] = htonl(afs_uuid.time_mid);
+       reply.ia.uuid[2] = htonl(afs_uuid.time_hi_and_version);
+       reply.ia.uuid[3] = htonl((s8) afs_uuid.clock_seq_hi_and_reserved);
+       reply.ia.uuid[4] = htonl((s8) afs_uuid.clock_seq_low);
+       for (loop = 0; loop < 6; loop++)
+               reply.ia.uuid[loop + 5] = htonl((s8) afs_uuid.node[loop]);
+
+       if (ifs) {
+               for (loop = 0; loop < nifs; loop++) {
+                       reply.ia.ifaddr[loop] = ifs[loop].address.s_addr;
+                       reply.ia.netmask[loop] = ifs[loop].netmask.s_addr;
+                       reply.ia.mtu[loop] = htonl(ifs[loop].mtu);
+               }
+               kfree(ifs);
+       }
+
+       reply.cap.capcount = htonl(1);
+       reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION);
+       afs_send_simple_reply(call, &reply, sizeof(reply));
+
+       _leave("");
+}
+
+/*
+ * deliver request data to a CB.TellMeAboutYourself call
+ */
+static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call,
+                                                struct sk_buff *skb, bool last)
+{
+       _enter(",{%u},%d", skb->len, last);
+
+       if (skb->len > 0)
+               return -EBADMSG;
+       if (!last)
+               return 0;
+
+       /* no unmarshalling required */
+       call->state = AFS_CALL_REPLYING;
+
+       INIT_WORK(&call->work, SRXAFSCB_TellMeAboutYourself);
+       schedule_work(&call->work);
+       return 0;
+}