Commit c024a811 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'dlm-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm

Pull dlm updates from David Teigland:
 "This set continues the ongoing rework of the low level communication
  layer in the dlm.

  The focus here is on improvements to connection handling, and
  reworking the receiving of messages"

* tag 'dlm-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm:
  fs: dlm: fix race in nodeid2con
  fs: dlm: rework receive handling
  fs: dlm: disallow buffer size below default
  fs: dlm: handle range check as callback
  fs: dlm: fix mark per nodeid setting
  fs: dlm: remove lock dependency warning
  fs: dlm: use free_con to free connection
  fs: dlm: handle possible othercon writequeues
  fs: dlm: move free writequeue into con free
  fs: dlm: fix configfs memory leak
  fs: dlm: fix dlm_local_addr memory leak
  fs: dlm: make connection hash lockless
  fs: dlm: synchronize dlm before shutdown
parents 6f5032a8 4f2b30fd
...@@ -4,6 +4,7 @@ menuconfig DLM ...@@ -4,6 +4,7 @@ menuconfig DLM
depends on INET depends on INET
depends on SYSFS && CONFIGFS_FS && (IPV6 || IPV6=n) depends on SYSFS && CONFIGFS_FS && (IPV6 || IPV6=n)
select IP_SCTP select IP_SCTP
select SRCU
help help
A general purpose distributed lock manager for kernel or userspace A general purpose distributed lock manager for kernel or userspace
applications. applications.
......
...@@ -125,7 +125,7 @@ static ssize_t cluster_cluster_name_store(struct config_item *item, ...@@ -125,7 +125,7 @@ static ssize_t cluster_cluster_name_store(struct config_item *item,
CONFIGFS_ATTR(cluster_, cluster_name); CONFIGFS_ATTR(cluster_, cluster_name);
static ssize_t cluster_set(struct dlm_cluster *cl, unsigned int *cl_field, static ssize_t cluster_set(struct dlm_cluster *cl, unsigned int *cl_field,
int *info_field, int check_zero, int *info_field, bool (*check_cb)(unsigned int x),
const char *buf, size_t len) const char *buf, size_t len)
{ {
unsigned int x; unsigned int x;
...@@ -137,7 +137,7 @@ static ssize_t cluster_set(struct dlm_cluster *cl, unsigned int *cl_field, ...@@ -137,7 +137,7 @@ static ssize_t cluster_set(struct dlm_cluster *cl, unsigned int *cl_field,
if (rc) if (rc)
return rc; return rc;
if (check_zero && !x) if (check_cb && check_cb(x))
return -EINVAL; return -EINVAL;
*cl_field = x; *cl_field = x;
...@@ -146,13 +146,13 @@ static ssize_t cluster_set(struct dlm_cluster *cl, unsigned int *cl_field, ...@@ -146,13 +146,13 @@ static ssize_t cluster_set(struct dlm_cluster *cl, unsigned int *cl_field,
return len; return len;
} }
#define CLUSTER_ATTR(name, check_zero) \ #define CLUSTER_ATTR(name, check_cb) \
static ssize_t cluster_##name##_store(struct config_item *item, \ static ssize_t cluster_##name##_store(struct config_item *item, \
const char *buf, size_t len) \ const char *buf, size_t len) \
{ \ { \
struct dlm_cluster *cl = config_item_to_cluster(item); \ struct dlm_cluster *cl = config_item_to_cluster(item); \
return cluster_set(cl, &cl->cl_##name, &dlm_config.ci_##name, \ return cluster_set(cl, &cl->cl_##name, &dlm_config.ci_##name, \
check_zero, buf, len); \ check_cb, buf, len); \
} \ } \
static ssize_t cluster_##name##_show(struct config_item *item, char *buf) \ static ssize_t cluster_##name##_show(struct config_item *item, char *buf) \
{ \ { \
...@@ -161,20 +161,30 @@ static ssize_t cluster_##name##_show(struct config_item *item, char *buf) \ ...@@ -161,20 +161,30 @@ static ssize_t cluster_##name##_show(struct config_item *item, char *buf) \
} \ } \
CONFIGFS_ATTR(cluster_, name); CONFIGFS_ATTR(cluster_, name);
CLUSTER_ATTR(tcp_port, 1); static bool dlm_check_zero(unsigned int x)
CLUSTER_ATTR(buffer_size, 1); {
CLUSTER_ATTR(rsbtbl_size, 1); return !x;
CLUSTER_ATTR(recover_timer, 1); }
CLUSTER_ATTR(toss_secs, 1);
CLUSTER_ATTR(scan_secs, 1); static bool dlm_check_buffer_size(unsigned int x)
CLUSTER_ATTR(log_debug, 0); {
CLUSTER_ATTR(log_info, 0); return (x < DEFAULT_BUFFER_SIZE);
CLUSTER_ATTR(protocol, 0); }
CLUSTER_ATTR(mark, 0);
CLUSTER_ATTR(timewarn_cs, 1); CLUSTER_ATTR(tcp_port, dlm_check_zero);
CLUSTER_ATTR(waitwarn_us, 0); CLUSTER_ATTR(buffer_size, dlm_check_buffer_size);
CLUSTER_ATTR(new_rsb_count, 0); CLUSTER_ATTR(rsbtbl_size, dlm_check_zero);
CLUSTER_ATTR(recover_callbacks, 0); CLUSTER_ATTR(recover_timer, dlm_check_zero);
CLUSTER_ATTR(toss_secs, dlm_check_zero);
CLUSTER_ATTR(scan_secs, dlm_check_zero);
CLUSTER_ATTR(log_debug, NULL);
CLUSTER_ATTR(log_info, NULL);
CLUSTER_ATTR(protocol, NULL);
CLUSTER_ATTR(mark, NULL);
CLUSTER_ATTR(timewarn_cs, dlm_check_zero);
CLUSTER_ATTR(waitwarn_us, NULL);
CLUSTER_ATTR(new_rsb_count, NULL);
CLUSTER_ATTR(recover_callbacks, NULL);
static struct configfs_attribute *cluster_attrs[] = { static struct configfs_attribute *cluster_attrs[] = {
[CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port, [CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port,
...@@ -221,6 +231,7 @@ struct dlm_space { ...@@ -221,6 +231,7 @@ struct dlm_space {
struct list_head members; struct list_head members;
struct mutex members_lock; struct mutex members_lock;
int members_count; int members_count;
struct dlm_nodes *nds;
}; };
struct dlm_comms { struct dlm_comms {
...@@ -430,6 +441,7 @@ static struct config_group *make_space(struct config_group *g, const char *name) ...@@ -430,6 +441,7 @@ static struct config_group *make_space(struct config_group *g, const char *name)
INIT_LIST_HEAD(&sp->members); INIT_LIST_HEAD(&sp->members);
mutex_init(&sp->members_lock); mutex_init(&sp->members_lock);
sp->members_count = 0; sp->members_count = 0;
sp->nds = nds;
return &sp->group; return &sp->group;
fail: fail:
...@@ -451,6 +463,7 @@ static void drop_space(struct config_group *g, struct config_item *i) ...@@ -451,6 +463,7 @@ static void drop_space(struct config_group *g, struct config_item *i)
static void release_space(struct config_item *i) static void release_space(struct config_item *i)
{ {
struct dlm_space *sp = config_item_to_space(i); struct dlm_space *sp = config_item_to_space(i);
kfree(sp->nds);
kfree(sp); kfree(sp);
} }
...@@ -857,18 +870,22 @@ int dlm_comm_seq(int nodeid, uint32_t *seq) ...@@ -857,18 +870,22 @@ int dlm_comm_seq(int nodeid, uint32_t *seq)
return 0; return 0;
} }
int dlm_comm_mark(int nodeid, unsigned int *mark) void dlm_comm_mark(int nodeid, unsigned int *mark)
{ {
struct dlm_comm *cm; struct dlm_comm *cm;
cm = get_comm(nodeid); cm = get_comm(nodeid);
if (!cm) if (!cm) {
return -ENOENT; *mark = dlm_config.ci_mark;
return;
}
*mark = cm->mark; if (cm->mark)
put_comm(cm); *mark = cm->mark;
else
*mark = dlm_config.ci_mark;
return 0; put_comm(cm);
} }
int dlm_our_nodeid(void) int dlm_our_nodeid(void)
...@@ -889,7 +906,6 @@ int dlm_our_addr(struct sockaddr_storage *addr, int num) ...@@ -889,7 +906,6 @@ int dlm_our_addr(struct sockaddr_storage *addr, int num)
/* Config file defaults */ /* Config file defaults */
#define DEFAULT_TCP_PORT 21064 #define DEFAULT_TCP_PORT 21064
#define DEFAULT_BUFFER_SIZE 4096
#define DEFAULT_RSBTBL_SIZE 1024 #define DEFAULT_RSBTBL_SIZE 1024
#define DEFAULT_RECOVER_TIMER 5 #define DEFAULT_RECOVER_TIMER 5
#define DEFAULT_TOSS_SECS 10 #define DEFAULT_TOSS_SECS 10
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#ifndef __CONFIG_DOT_H__ #ifndef __CONFIG_DOT_H__
#define __CONFIG_DOT_H__ #define __CONFIG_DOT_H__
#define DEFAULT_BUFFER_SIZE 4096
struct dlm_config_node { struct dlm_config_node {
int nodeid; int nodeid;
int weight; int weight;
...@@ -46,7 +48,7 @@ void dlm_config_exit(void); ...@@ -46,7 +48,7 @@ void dlm_config_exit(void);
int dlm_config_nodes(char *lsname, struct dlm_config_node **nodes_out, int dlm_config_nodes(char *lsname, struct dlm_config_node **nodes_out,
int *count_out); int *count_out);
int dlm_comm_seq(int nodeid, uint32_t *seq); int dlm_comm_seq(int nodeid, uint32_t *seq);
int dlm_comm_mark(int nodeid, unsigned int *mark); void dlm_comm_mark(int nodeid, unsigned int *mark);
int dlm_our_nodeid(void); int dlm_our_nodeid(void);
int dlm_our_addr(struct sockaddr_storage *addr, int num); int dlm_our_addr(struct sockaddr_storage *addr, int num);
......
This diff is collapsed.
...@@ -22,114 +22,84 @@ ...@@ -22,114 +22,84 @@
* into packets and sends them to the comms layer. * into packets and sends them to the comms layer.
*/ */
#include <asm/unaligned.h>
#include "dlm_internal.h" #include "dlm_internal.h"
#include "lowcomms.h" #include "lowcomms.h"
#include "config.h" #include "config.h"
#include "lock.h" #include "lock.h"
#include "midcomms.h" #include "midcomms.h"
static void copy_from_cb(void *dst, const void *base, unsigned offset,
unsigned len, unsigned limit)
{
unsigned copy = len;
if ((copy + offset) > limit)
copy = limit - offset;
memcpy(dst, base + offset, copy);
len -= copy;
if (len)
memcpy(dst + copy, base, len);
}
/* /*
* Called from the low-level comms layer to process a buffer of * Called from the low-level comms layer to process a buffer of
* commands. * commands.
*
* Only complete messages are processed here, any "spare" bytes from
* the end of a buffer are saved and tacked onto the front of the next
* message that comes in. I doubt this will happen very often but we
* need to be able to cope with it and I don't want the task to be waiting
* for packets to come in when there is useful work to be done.
*/ */
int dlm_process_incoming_buffer(int nodeid, const void *base, int dlm_process_incoming_buffer(int nodeid, unsigned char *buf, int len)
unsigned offset, unsigned len, unsigned limit)
{ {
union { const unsigned char *ptr = buf;
unsigned char __buf[DLM_INBUF_LEN]; const struct dlm_header *hd;
/* this is to force proper alignment on some arches */
union dlm_packet p;
} __tmp;
union dlm_packet *p = &__tmp.p;
int ret = 0;
int err = 0;
uint16_t msglen; uint16_t msglen;
uint32_t lockspace; int ret = 0;
while (len > sizeof(struct dlm_header)) {
/* Copy just the header to check the total length. The
message may wrap around the end of the buffer back to the
start, so we need to use a temp buffer and copy_from_cb. */
copy_from_cb(p, base, offset, sizeof(struct dlm_header),
limit);
msglen = le16_to_cpu(p->header.h_length);
lockspace = p->header.h_lockspace;
err = -EINVAL; while (len >= sizeof(struct dlm_header)) {
if (msglen < sizeof(struct dlm_header)) hd = (struct dlm_header *)ptr;
break;
if (p->header.h_cmd == DLM_MSG) { /* no message should be more than this otherwise we
if (msglen < sizeof(struct dlm_message)) * cannot deliver this message to upper layers
break; */
} else { msglen = get_unaligned_le16(&hd->h_length);
if (msglen < sizeof(struct dlm_rcom)) if (msglen > DEFAULT_BUFFER_SIZE) {
break; log_print("received invalid length header: %u, will abort message parsing",
} msglen);
err = -E2BIG; return -EBADMSG;
if (msglen > dlm_config.ci_buffer_size) {
log_print("message size %d from %d too big, buf len %d",
msglen, nodeid, len);
break;
} }
err = 0;
/* If only part of the full message is contained in this
buffer, then do nothing and wait for lowcomms to call
us again later with more data. We return 0 meaning
we've consumed none of the input buffer. */
/* caller will take care that leftover
* will be parsed next call with more data
*/
if (msglen > len) if (msglen > len)
break; break;
/* Allocate a larger temp buffer if the full message won't fit switch (hd->h_cmd) {
in the buffer on the stack (which should work for most case DLM_MSG:
ordinary messages). */ if (msglen < sizeof(struct dlm_message)) {
log_print("dlm msg too small: %u, will skip this message",
if (msglen > sizeof(__tmp) && p == &__tmp.p) { msglen);
p = kmalloc(dlm_config.ci_buffer_size, GFP_NOFS); goto skip;
if (p == NULL) }
return ret;
}
copy_from_cb(p, base, offset, msglen, limit); break;
case DLM_RCOM:
if (msglen < sizeof(struct dlm_rcom)) {
log_print("dlm rcom msg too small: %u, will skip this message",
msglen);
goto skip;
}
BUG_ON(lockspace != p->header.h_lockspace); break;
default:
log_print("unsupported h_cmd received: %u, will skip this message",
hd->h_cmd);
goto skip;
}
/* for aligned memory access, we just copy current message
* to begin of the buffer which contains already parsed buffer
* data and should provide align access for upper layers
* because the start address of the buffer has a aligned
* address. This memmove can be removed when the upperlayer
* is capable of unaligned memory access.
*/
memmove(buf, ptr, msglen);
dlm_receive_buffer((union dlm_packet *)buf, nodeid);
skip:
ret += msglen; ret += msglen;
offset += msglen;
offset &= (limit - 1);
len -= msglen; len -= msglen;
ptr += msglen;
dlm_receive_buffer(p, nodeid);
} }
if (p != &__tmp.p) return ret;
kfree(p);
return err ? err : ret;
} }
...@@ -12,8 +12,7 @@ ...@@ -12,8 +12,7 @@
#ifndef __MIDCOMMS_DOT_H__ #ifndef __MIDCOMMS_DOT_H__
#define __MIDCOMMS_DOT_H__ #define __MIDCOMMS_DOT_H__
int dlm_process_incoming_buffer(int nodeid, const void *base, unsigned offset, int dlm_process_incoming_buffer(int nodeid, unsigned char *buf, int buflen);
unsigned len, unsigned limit);
#endif /* __MIDCOMMS_DOT_H__ */ #endif /* __MIDCOMMS_DOT_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment