mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
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
This commit is contained in:
@@ -4,6 +4,7 @@ menuconfig DLM
|
||||
depends on INET
|
||||
depends on SYSFS && CONFIGFS_FS && (IPV6 || IPV6=n)
|
||||
select IP_SCTP
|
||||
select SRCU
|
||||
help
|
||||
A general purpose distributed lock manager for kernel or userspace
|
||||
applications.
|
||||
|
||||
+41
-25
@@ -125,7 +125,7 @@ static ssize_t cluster_cluster_name_store(struct config_item *item,
|
||||
CONFIGFS_ATTR(cluster_, cluster_name);
|
||||
|
||||
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)
|
||||
{
|
||||
unsigned int x;
|
||||
@@ -137,7 +137,7 @@ static ssize_t cluster_set(struct dlm_cluster *cl, unsigned int *cl_field,
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (check_zero && !x)
|
||||
if (check_cb && check_cb(x))
|
||||
return -EINVAL;
|
||||
|
||||
*cl_field = x;
|
||||
@@ -146,13 +146,13 @@ static ssize_t cluster_set(struct dlm_cluster *cl, unsigned int *cl_field,
|
||||
return len;
|
||||
}
|
||||
|
||||
#define CLUSTER_ATTR(name, check_zero) \
|
||||
#define CLUSTER_ATTR(name, check_cb) \
|
||||
static ssize_t cluster_##name##_store(struct config_item *item, \
|
||||
const char *buf, size_t len) \
|
||||
{ \
|
||||
struct dlm_cluster *cl = config_item_to_cluster(item); \
|
||||
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) \
|
||||
{ \
|
||||
@@ -161,20 +161,30 @@ static ssize_t cluster_##name##_show(struct config_item *item, char *buf) \
|
||||
} \
|
||||
CONFIGFS_ATTR(cluster_, name);
|
||||
|
||||
CLUSTER_ATTR(tcp_port, 1);
|
||||
CLUSTER_ATTR(buffer_size, 1);
|
||||
CLUSTER_ATTR(rsbtbl_size, 1);
|
||||
CLUSTER_ATTR(recover_timer, 1);
|
||||
CLUSTER_ATTR(toss_secs, 1);
|
||||
CLUSTER_ATTR(scan_secs, 1);
|
||||
CLUSTER_ATTR(log_debug, 0);
|
||||
CLUSTER_ATTR(log_info, 0);
|
||||
CLUSTER_ATTR(protocol, 0);
|
||||
CLUSTER_ATTR(mark, 0);
|
||||
CLUSTER_ATTR(timewarn_cs, 1);
|
||||
CLUSTER_ATTR(waitwarn_us, 0);
|
||||
CLUSTER_ATTR(new_rsb_count, 0);
|
||||
CLUSTER_ATTR(recover_callbacks, 0);
|
||||
static bool dlm_check_zero(unsigned int x)
|
||||
{
|
||||
return !x;
|
||||
}
|
||||
|
||||
static bool dlm_check_buffer_size(unsigned int x)
|
||||
{
|
||||
return (x < DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
CLUSTER_ATTR(tcp_port, dlm_check_zero);
|
||||
CLUSTER_ATTR(buffer_size, dlm_check_buffer_size);
|
||||
CLUSTER_ATTR(rsbtbl_size, dlm_check_zero);
|
||||
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[] = {
|
||||
[CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port,
|
||||
@@ -221,6 +231,7 @@ struct dlm_space {
|
||||
struct list_head members;
|
||||
struct mutex members_lock;
|
||||
int members_count;
|
||||
struct dlm_nodes *nds;
|
||||
};
|
||||
|
||||
struct dlm_comms {
|
||||
@@ -430,6 +441,7 @@ static struct config_group *make_space(struct config_group *g, const char *name)
|
||||
INIT_LIST_HEAD(&sp->members);
|
||||
mutex_init(&sp->members_lock);
|
||||
sp->members_count = 0;
|
||||
sp->nds = nds;
|
||||
return &sp->group;
|
||||
|
||||
fail:
|
||||
@@ -451,6 +463,7 @@ static void drop_space(struct config_group *g, struct config_item *i)
|
||||
static void release_space(struct config_item *i)
|
||||
{
|
||||
struct dlm_space *sp = config_item_to_space(i);
|
||||
kfree(sp->nds);
|
||||
kfree(sp);
|
||||
}
|
||||
|
||||
@@ -857,18 +870,22 @@ int dlm_comm_seq(int nodeid, uint32_t *seq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dlm_comm_mark(int nodeid, unsigned int *mark)
|
||||
void dlm_comm_mark(int nodeid, unsigned int *mark)
|
||||
{
|
||||
struct dlm_comm *cm;
|
||||
|
||||
cm = get_comm(nodeid);
|
||||
if (!cm)
|
||||
return -ENOENT;
|
||||
if (!cm) {
|
||||
*mark = dlm_config.ci_mark;
|
||||
return;
|
||||
}
|
||||
|
||||
if (cm->mark)
|
||||
*mark = cm->mark;
|
||||
else
|
||||
*mark = dlm_config.ci_mark;
|
||||
|
||||
*mark = cm->mark;
|
||||
put_comm(cm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dlm_our_nodeid(void)
|
||||
@@ -889,7 +906,6 @@ int dlm_our_addr(struct sockaddr_storage *addr, int num)
|
||||
|
||||
/* Config file defaults */
|
||||
#define DEFAULT_TCP_PORT 21064
|
||||
#define DEFAULT_BUFFER_SIZE 4096
|
||||
#define DEFAULT_RSBTBL_SIZE 1024
|
||||
#define DEFAULT_RECOVER_TIMER 5
|
||||
#define DEFAULT_TOSS_SECS 10
|
||||
|
||||
+3
-1
@@ -12,6 +12,8 @@
|
||||
#ifndef __CONFIG_DOT_H__
|
||||
#define __CONFIG_DOT_H__
|
||||
|
||||
#define DEFAULT_BUFFER_SIZE 4096
|
||||
|
||||
struct dlm_config_node {
|
||||
int nodeid;
|
||||
int weight;
|
||||
@@ -46,7 +48,7 @@ void dlm_config_exit(void);
|
||||
int dlm_config_nodes(char *lsname, struct dlm_config_node **nodes_out,
|
||||
int *count_out);
|
||||
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_addr(struct sockaddr_storage *addr, int num);
|
||||
|
||||
|
||||
+161
-168
File diff suppressed because it is too large
Load Diff
+51
-81
@@ -22,114 +22,84 @@
|
||||
* into packets and sends them to the comms layer.
|
||||
*/
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "dlm_internal.h"
|
||||
#include "lowcomms.h"
|
||||
#include "config.h"
|
||||
#include "lock.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
|
||||
* 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,
|
||||
unsigned offset, unsigned len, unsigned limit)
|
||||
int dlm_process_incoming_buffer(int nodeid, unsigned char *buf, int len)
|
||||
{
|
||||
union {
|
||||
unsigned char __buf[DLM_INBUF_LEN];
|
||||
/* 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;
|
||||
const unsigned char *ptr = buf;
|
||||
const struct dlm_header *hd;
|
||||
uint16_t msglen;
|
||||
uint32_t lockspace;
|
||||
int ret = 0;
|
||||
|
||||
while (len > sizeof(struct dlm_header)) {
|
||||
while (len >= sizeof(struct dlm_header)) {
|
||||
hd = (struct dlm_header *)ptr;
|
||||
|
||||
/* 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;
|
||||
if (msglen < sizeof(struct dlm_header))
|
||||
break;
|
||||
if (p->header.h_cmd == DLM_MSG) {
|
||||
if (msglen < sizeof(struct dlm_message))
|
||||
break;
|
||||
} else {
|
||||
if (msglen < sizeof(struct dlm_rcom))
|
||||
break;
|
||||
/* no message should be more than this otherwise we
|
||||
* cannot deliver this message to upper layers
|
||||
*/
|
||||
msglen = get_unaligned_le16(&hd->h_length);
|
||||
if (msglen > DEFAULT_BUFFER_SIZE) {
|
||||
log_print("received invalid length header: %u, will abort message parsing",
|
||||
msglen);
|
||||
return -EBADMSG;
|
||||
}
|
||||
err = -E2BIG;
|
||||
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)
|
||||
break;
|
||||
|
||||
/* Allocate a larger temp buffer if the full message won't fit
|
||||
in the buffer on the stack (which should work for most
|
||||
ordinary messages). */
|
||||
switch (hd->h_cmd) {
|
||||
case DLM_MSG:
|
||||
if (msglen < sizeof(struct dlm_message)) {
|
||||
log_print("dlm msg too small: %u, will skip this message",
|
||||
msglen);
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if (msglen > sizeof(__tmp) && p == &__tmp.p) {
|
||||
p = kmalloc(dlm_config.ci_buffer_size, GFP_NOFS);
|
||||
if (p == NULL)
|
||||
return ret;
|
||||
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;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
log_print("unsupported h_cmd received: %u, will skip this message",
|
||||
hd->h_cmd);
|
||||
goto skip;
|
||||
}
|
||||
|
||||
copy_from_cb(p, base, offset, msglen, limit);
|
||||
|
||||
BUG_ON(lockspace != p->header.h_lockspace);
|
||||
/* 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;
|
||||
offset += msglen;
|
||||
offset &= (limit - 1);
|
||||
len -= msglen;
|
||||
|
||||
dlm_receive_buffer(p, nodeid);
|
||||
ptr += msglen;
|
||||
}
|
||||
|
||||
if (p != &__tmp.p)
|
||||
kfree(p);
|
||||
|
||||
return err ? err : ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -12,8 +12,7 @@
|
||||
#ifndef __MIDCOMMS_DOT_H__
|
||||
#define __MIDCOMMS_DOT_H__
|
||||
|
||||
int dlm_process_incoming_buffer(int nodeid, const void *base, unsigned offset,
|
||||
unsigned len, unsigned limit);
|
||||
int dlm_process_incoming_buffer(int nodeid, unsigned char *buf, int buflen);
|
||||
|
||||
#endif /* __MIDCOMMS_DOT_H__ */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user