- lvmlockd守护进程使用LVM内部的libdaemon库实现与命令行程序的通信,为LVM命令提供分布式锁功能。
- lvmlockd的具体实现依赖sanlock(依赖wdmd服务)和dlm(依赖CoroSync、PaceMaker和Fence设备)。
- lvmlockd必须配合LVM的本地锁(flock)使用,是本地锁在集群环境下的扩充。
- lvmlockd的作者也是sanlock的原作者,发起此项目的目的是替代clvmd,使得用户在dlm外有更多选择(但从他的源码结构来看,没有使用一个好的抽象接口,很难扩充第三种锁的支持,我认为这不是一个好的设计)。
- lvmlockd可以和lvmetad共存,但clvmd却不可以(原因未知,我并没有分析出他们为什么不能共存)。
- lvmlockd的功能没有使用LVM的锁抽象接口来实现,而是直接插入LVM源码中(我认为这不是个好的设计)。
上层接口函数
上层接口函数为LVM命令提供了与lvmlockd守护进程建立连接,并使用其提供的所服务的功能,这些函数的调用分布在LVM命令的所有需要锁的环节。
连接和断开服务
$ cat daemons/lvmlockd/lvmlockd-client.h
...
#define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket"
/* Wrappers to open/close connection */
static inline daemon_handle lvmlockd_open(const char *sock)
{
daemon_info lvmlockd_info = {
.path = "lvmlockd",
.socket = sock ?: LVMLOCKD_SOCKET,
.protocol = "lvmlockd",
.protocol_version = 1,
.autostart = 0
};
return daemon_open(lvmlockd_info);
}
static inline void lvmlockd_close(daemon_handle h)
{
return daemon_close(h);
}
...
锁操作
$ cat lib/locking/lvmlockd.h
...
/* vgcreate/vgremove use init/free */
int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg, const char *lock_type, int lv_lock_count);
int lockd_free_vg_before(struct cmd_context *cmd, struct volume_group *vg, int changing);
void lockd_free_vg_final(struct cmd_context *cmd, struct volume_group *vg);
/* vgrename */
int lockd_rename_vg_before(struct cmd_context *cmd, struct volume_group *vg);
int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int success);
/* start and stop the lockspace for a vg */
int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg, int start_init);
int lockd_stop_vg(struct cmd_context *cmd, struct volume_group *vg);
int lockd_start_wait(struct cmd_context *cmd);
/* locking */
int lockd_gl_create(struct cmd_context *cmd, const char *def_mode, const char *vg_lock_type);
int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags);
int lockd_vg(struct cmd_context *cmd, const char *vg_name, const char *def_mode,
uint32_t flags, uint32_t *lockd_state);
int lockd_vg_update(struct volume_group *vg);
int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg,
const char *lv_name, struct id *lv_id,
const char *lock_args, const char *def_mode, uint32_t flags);
int lockd_lv(struct cmd_context *cmd, struct logical_volume *lv,
const char *def_mode, uint32_t flags);
/* lvcreate/lvremove use init/free */
int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv,
struct lvcreate_params *lp);
int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv, const char *lock_type, const char **lock_args);
int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg,
const char *lv_name, struct id *lv_id, const char *lock_args);
const char *lockd_running_lock_type(struct cmd_context *cmd, int *found_multiple);
int handle_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg);
int lockd_lv_uses_lock(struct logical_volume *lv);
...
内部数据结构
锁定范围(对象)
- 全局
- 卷组
- 逻辑卷
$ cat daemons/lvmlockd/lvmlockd-internal.h
...
/* resource types */
enum {
LD_RT_GL = 1,
LD_RT_VG,
LD_RT_LV,
};
...
锁定模式(状态)
- 无效
- 解锁
- 空锁
- 共享
- 独占
...
/* lock modes, more restrictive must be larger value */
enum {
LD_LK_IV = -1,
LD_LK_UN = 0,
LD_LK_NL = 1,
LD_LK_SH = 2,
LD_LK_EX = 3,
};
...
锁管理器类型
目前只支持DLM和sanlock。
...
/* lock manager types */
enum {
LD_LM_NONE = 0,
LD_LM_UNUSED = 1, /* place holder so values match lib/locking/lvmlockd.h */
LD_LM_DLM = 2,
LD_LM_SANLOCK = 3,
};
...
客户端管理
每个客户端连接对应一个。
...
struct list_head {
struct list_head *next, *prev;
};
struct client {
struct list_head list;
pthread_mutex_t mutex;
int pid;
int fd;
int pi;
uint32_t id;
unsigned int recv : 1;
unsigned int dead : 1;
unsigned int poll_ignore : 1;
unsigned int lock_ops : 1;
char name[MAX_NAME+1];
};
...
动作(报文)
每个客户端的请求都被填充为一个请求。
类型
...
/* operation types */
enum {
LD_OP_HELLO = 1,
LD_OP_QUIT,
LD_OP_INIT,
LD_OP_FREE,
LD_OP_START,
LD_OP_STOP,
LD_OP_LOCK,
LD_OP_UPDATE,
LD_OP_CLOSE,
LD_OP_ENABLE,
LD_OP_DISABLE,
LD_OP_START_WAIT,
LD_OP_STOP