linux/fs/dlm/midcomms.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/******************************************************************************
   3*******************************************************************************
   4**
   5**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
   6**  Copyright (C) 2004-2008 Red Hat, Inc.  All rights reserved.
   7**
   8**
   9*******************************************************************************
  10******************************************************************************/
  11
  12/*
  13 * midcomms.c
  14 *
  15 * This is the appallingly named "mid-level" comms layer.
  16 *
  17 * Its purpose is to take packets from the "real" comms layer,
  18 * split them up into packets and pass them to the interested
  19 * part of the locking mechanism.
  20 *
  21 * It also takes messages from the locking layer, formats them
  22 * into packets and sends them to the comms layer.
  23 */
  24
  25#include "dlm_internal.h"
  26#include "lowcomms.h"
  27#include "config.h"
  28#include "lock.h"
  29#include "midcomms.h"
  30
  31
  32static void copy_from_cb(void *dst, const void *base, unsigned offset,
  33                         unsigned len, unsigned limit)
  34{
  35        unsigned copy = len;
  36
  37        if ((copy + offset) > limit)
  38                copy = limit - offset;
  39        memcpy(dst, base + offset, copy);
  40        len -= copy;
  41        if (len)
  42                memcpy(dst + copy, base, len);
  43}
  44
  45/*
  46 * Called from the low-level comms layer to process a buffer of
  47 * commands.
  48 *
  49 * Only complete messages are processed here, any "spare" bytes from
  50 * the end of a buffer are saved and tacked onto the front of the next
  51 * message that comes in. I doubt this will happen very often but we
  52 * need to be able to cope with it and I don't want the task to be waiting
  53 * for packets to come in when there is useful work to be done.
  54 */
  55
  56int dlm_process_incoming_buffer(int nodeid, const void *base,
  57                                unsigned offset, unsigned len, unsigned limit)
  58{
  59        union {
  60                unsigned char __buf[DLM_INBUF_LEN];
  61                /* this is to force proper alignment on some arches */
  62                union dlm_packet p;
  63        } __tmp;
  64        union dlm_packet *p = &__tmp.p;
  65        int ret = 0;
  66        int err = 0;
  67        uint16_t msglen;
  68        uint32_t lockspace;
  69
  70        while (len > sizeof(struct dlm_header)) {
  71
  72                /* Copy just the header to check the total length.  The
  73                   message may wrap around the end of the buffer back to the
  74                   start, so we need to use a temp buffer and copy_from_cb. */
  75
  76                copy_from_cb(p, base, offset, sizeof(struct dlm_header),
  77                             limit);
  78
  79                msglen = le16_to_cpu(p->header.h_length);
  80                lockspace = p->header.h_lockspace;
  81
  82                err = -EINVAL;
  83                if (msglen < sizeof(struct dlm_header))
  84                        break;
  85                if (p->header.h_cmd == DLM_MSG) {
  86                        if (msglen < sizeof(struct dlm_message))
  87                                break;
  88                } else {
  89                        if (msglen < sizeof(struct dlm_rcom))
  90                                break;
  91                }
  92                err = -E2BIG;
  93                if (msglen > dlm_config.ci_buffer_size) {
  94                        log_print("message size %d from %d too big, buf len %d",
  95                                  msglen, nodeid, len);
  96                        break;
  97                }
  98                err = 0;
  99
 100                /* If only part of the full message is contained in this
 101                   buffer, then do nothing and wait for lowcomms to call
 102                   us again later with more data.  We return 0 meaning
 103                   we've consumed none of the input buffer. */
 104
 105                if (msglen > len)
 106                        break;
 107
 108                /* Allocate a larger temp buffer if the full message won't fit
 109                   in the buffer on the stack (which should work for most
 110                   ordinary messages). */
 111
 112                if (msglen > sizeof(__tmp) && p == &__tmp.p) {
 113                        p = kmalloc(dlm_config.ci_buffer_size, GFP_NOFS);
 114                        if (p == NULL)
 115                                return ret;
 116                }
 117
 118                copy_from_cb(p, base, offset, msglen, limit);
 119
 120                BUG_ON(lockspace != p->header.h_lockspace);
 121
 122                ret += msglen;
 123                offset += msglen;
 124                offset &= (limit - 1);
 125                len -= msglen;
 126
 127                dlm_receive_buffer(p, nodeid);
 128        }
 129
 130        if (p != &__tmp.p)
 131                kfree(p);
 132
 133        return err ? err : ret;
 134}
 135
 136