Commit f4309528 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull dlm updates from David Teigland:

 - Fix a couple races found with a new torture test

 - Improve errors when api functions are used incorrectly

 - Improve tracing for lock requests from user space

 - Fix use after free in recently added tracing cod.

 - Small internal code cleanups

* tag 'dlm-6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/linux-dlm:
  fs: dlm: fix possible use after free if tracing
  fs: dlm: const void resource name parameter
  fs: dlm: LSFL_CB_DELAY only for kernel lockspaces
  fs: dlm: remove DLM_LSFL_FS from uapi
  fs: dlm: trace user space callbacks
  fs: dlm: change ls_clear_proc_locks to spinlock
  fs: dlm: remove dlm_del_ast prototype
  fs: dlm: handle rcom in else if branch
  fs: dlm: allow lockspaces have zero lvblen
  fs: dlm: fix invalid derefence of sb_lvbptr
  fs: dlm: handle -EINVAL as log_error()
  fs: dlm: use __func__ for function name
  fs: dlm: handle -EBUSY first in unlock validation
  fs: dlm: handle -EBUSY first in lock arg validation
  fs: dlm: fix race between test_bit() and queue_work()
  fs: dlm: fix race in lowcomms
parents f90497a1 3b761030
...@@ -876,8 +876,8 @@ static int join(struct mddev *mddev, int nodes) ...@@ -876,8 +876,8 @@ static int join(struct mddev *mddev, int nodes)
memset(str, 0, 64); memset(str, 0, 64);
sprintf(str, "%pU", mddev->uuid); sprintf(str, "%pU", mddev->uuid);
ret = dlm_new_lockspace(str, mddev->bitmap_info.cluster_name, ret = dlm_new_lockspace(str, mddev->bitmap_info.cluster_name,
DLM_LSFL_FS, LVB_SIZE, 0, LVB_SIZE, &md_ls_ops, mddev,
&md_ls_ops, mddev, &ops_rv, &cinfo->lockspace); &ops_rv, &cinfo->lockspace);
if (ret) if (ret)
goto err; goto err;
wait_for_completion(&cinfo->completion); wait_for_completion(&cinfo->completion);
......
...@@ -200,13 +200,13 @@ void dlm_add_cb(struct dlm_lkb *lkb, uint32_t flags, int mode, int status, ...@@ -200,13 +200,13 @@ void dlm_add_cb(struct dlm_lkb *lkb, uint32_t flags, int mode, int status,
if (!prev_seq) { if (!prev_seq) {
kref_get(&lkb->lkb_ref); kref_get(&lkb->lkb_ref);
mutex_lock(&ls->ls_cb_mutex);
if (test_bit(LSFL_CB_DELAY, &ls->ls_flags)) { if (test_bit(LSFL_CB_DELAY, &ls->ls_flags)) {
mutex_lock(&ls->ls_cb_mutex);
list_add(&lkb->lkb_cb_list, &ls->ls_cb_delay); list_add(&lkb->lkb_cb_list, &ls->ls_cb_delay);
mutex_unlock(&ls->ls_cb_mutex);
} else { } else {
queue_work(ls->ls_callback_wq, &lkb->lkb_cb_work); queue_work(ls->ls_callback_wq, &lkb->lkb_cb_work);
} }
mutex_unlock(&ls->ls_cb_mutex);
} }
out: out:
mutex_unlock(&lkb->lkb_cb_mutex); mutex_unlock(&lkb->lkb_cb_mutex);
...@@ -288,10 +288,13 @@ void dlm_callback_stop(struct dlm_ls *ls) ...@@ -288,10 +288,13 @@ void dlm_callback_stop(struct dlm_ls *ls)
void dlm_callback_suspend(struct dlm_ls *ls) void dlm_callback_suspend(struct dlm_ls *ls)
{ {
set_bit(LSFL_CB_DELAY, &ls->ls_flags); if (ls->ls_callback_wq) {
mutex_lock(&ls->ls_cb_mutex);
set_bit(LSFL_CB_DELAY, &ls->ls_flags);
mutex_unlock(&ls->ls_cb_mutex);
if (ls->ls_callback_wq)
flush_workqueue(ls->ls_callback_wq); flush_workqueue(ls->ls_callback_wq);
}
} }
#define MAX_CB_QUEUE 25 #define MAX_CB_QUEUE 25
...@@ -302,11 +305,11 @@ void dlm_callback_resume(struct dlm_ls *ls) ...@@ -302,11 +305,11 @@ void dlm_callback_resume(struct dlm_ls *ls)
int count = 0, sum = 0; int count = 0, sum = 0;
bool empty; bool empty;
clear_bit(LSFL_CB_DELAY, &ls->ls_flags);
if (!ls->ls_callback_wq) if (!ls->ls_callback_wq)
return; return;
clear_bit(LSFL_CB_DELAY, &ls->ls_flags);
more: more:
mutex_lock(&ls->ls_cb_mutex); mutex_lock(&ls->ls_cb_mutex);
list_for_each_entry_safe(lkb, safe, &ls->ls_cb_delay, lkb_cb_list) { list_for_each_entry_safe(lkb, safe, &ls->ls_cb_delay, lkb_cb_list) {
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#ifndef __ASTD_DOT_H__ #ifndef __ASTD_DOT_H__
#define __ASTD_DOT_H__ #define __ASTD_DOT_H__
void dlm_del_ast(struct dlm_lkb *lkb);
int dlm_add_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode, int dlm_add_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
int status, uint32_t sbflags, uint64_t seq); int status, uint32_t sbflags, uint64_t seq);
int dlm_rem_lkb_callback(struct dlm_ls *ls, struct dlm_lkb *lkb, int dlm_rem_lkb_callback(struct dlm_ls *ls, struct dlm_lkb *lkb,
......
...@@ -661,7 +661,7 @@ struct dlm_ls { ...@@ -661,7 +661,7 @@ struct dlm_ls {
spinlock_t ls_recover_idr_lock; spinlock_t ls_recover_idr_lock;
wait_queue_head_t ls_wait_general; wait_queue_head_t ls_wait_general;
wait_queue_head_t ls_recover_lock_wait; wait_queue_head_t ls_recover_lock_wait;
struct mutex ls_clear_proc_locks; spinlock_t ls_clear_proc_locks;
struct list_head ls_root_list; /* root resources */ struct list_head ls_root_list; /* root resources */
struct rw_semaphore ls_root_sem; /* protect root_list */ struct rw_semaphore ls_root_sem; /* protect root_list */
......
This diff is collapsed.
...@@ -36,7 +36,7 @@ static inline void dlm_adjust_timeouts(struct dlm_ls *ls) { } ...@@ -36,7 +36,7 @@ static inline void dlm_adjust_timeouts(struct dlm_ls *ls) { }
int dlm_master_lookup(struct dlm_ls *ls, int nodeid, char *name, int len, int dlm_master_lookup(struct dlm_ls *ls, int nodeid, char *name, int len,
unsigned int flags, int *r_nodeid, int *result); unsigned int flags, int *r_nodeid, int *result);
int dlm_search_rsb_tree(struct rb_root *tree, char *name, int len, int dlm_search_rsb_tree(struct rb_root *tree, const void *name, int len,
struct dlm_rsb **r_ret); struct dlm_rsb **r_ret);
void dlm_recover_purge(struct dlm_ls *ls); void dlm_recover_purge(struct dlm_ls *ls);
......
...@@ -416,7 +416,7 @@ static int new_lockspace(const char *name, const char *cluster, ...@@ -416,7 +416,7 @@ static int new_lockspace(const char *name, const char *cluster,
if (namelen > DLM_LOCKSPACE_LEN || namelen == 0) if (namelen > DLM_LOCKSPACE_LEN || namelen == 0)
return -EINVAL; return -EINVAL;
if (!lvblen || (lvblen % 8)) if (lvblen % 8)
return -EINVAL; return -EINVAL;
if (!try_module_get(THIS_MODULE)) if (!try_module_get(THIS_MODULE))
...@@ -584,7 +584,7 @@ static int new_lockspace(const char *name, const char *cluster, ...@@ -584,7 +584,7 @@ static int new_lockspace(const char *name, const char *cluster,
atomic_set(&ls->ls_requestqueue_cnt, 0); atomic_set(&ls->ls_requestqueue_cnt, 0);
init_waitqueue_head(&ls->ls_requestqueue_wait); init_waitqueue_head(&ls->ls_requestqueue_wait);
mutex_init(&ls->ls_requestqueue_mutex); mutex_init(&ls->ls_requestqueue_mutex);
mutex_init(&ls->ls_clear_proc_locks); spin_lock_init(&ls->ls_clear_proc_locks);
/* Due backwards compatibility with 3.1 we need to use maximum /* Due backwards compatibility with 3.1 we need to use maximum
* possible dlm message size to be sure the message will fit and * possible dlm message size to be sure the message will fit and
...@@ -703,10 +703,11 @@ static int new_lockspace(const char *name, const char *cluster, ...@@ -703,10 +703,11 @@ static int new_lockspace(const char *name, const char *cluster,
return error; return error;
} }
int dlm_new_lockspace(const char *name, const char *cluster, static int __dlm_new_lockspace(const char *name, const char *cluster,
uint32_t flags, int lvblen, uint32_t flags, int lvblen,
const struct dlm_lockspace_ops *ops, void *ops_arg, const struct dlm_lockspace_ops *ops,
int *ops_result, dlm_lockspace_t **lockspace) void *ops_arg, int *ops_result,
dlm_lockspace_t **lockspace)
{ {
int error = 0; int error = 0;
...@@ -732,6 +733,25 @@ int dlm_new_lockspace(const char *name, const char *cluster, ...@@ -732,6 +733,25 @@ int dlm_new_lockspace(const char *name, const char *cluster,
return error; return error;
} }
int dlm_new_lockspace(const char *name, const char *cluster, uint32_t flags,
int lvblen, const struct dlm_lockspace_ops *ops,
void *ops_arg, int *ops_result,
dlm_lockspace_t **lockspace)
{
return __dlm_new_lockspace(name, cluster, flags | DLM_LSFL_FS, lvblen,
ops, ops_arg, ops_result, lockspace);
}
int dlm_new_user_lockspace(const char *name, const char *cluster,
uint32_t flags, int lvblen,
const struct dlm_lockspace_ops *ops,
void *ops_arg, int *ops_result,
dlm_lockspace_t **lockspace)
{
return __dlm_new_lockspace(name, cluster, flags, lvblen, ops,
ops_arg, ops_result, lockspace);
}
static int lkb_idr_is_local(int id, void *p, void *data) static int lkb_idr_is_local(int id, void *p, void *data)
{ {
struct dlm_lkb *lkb = p; struct dlm_lkb *lkb = p;
......
...@@ -12,6 +12,14 @@ ...@@ -12,6 +12,14 @@
#ifndef __LOCKSPACE_DOT_H__ #ifndef __LOCKSPACE_DOT_H__
#define __LOCKSPACE_DOT_H__ #define __LOCKSPACE_DOT_H__
/* DLM_LSFL_FS
* The lockspace user is in the kernel (i.e. filesystem). Enables
* direct bast/cast callbacks.
*
* internal lockspace flag - will be removed in future
*/
#define DLM_LSFL_FS 0x00000004
int dlm_lockspace_init(void); int dlm_lockspace_init(void);
void dlm_lockspace_exit(void); void dlm_lockspace_exit(void);
struct dlm_ls *dlm_find_lockspace_global(uint32_t id); struct dlm_ls *dlm_find_lockspace_global(uint32_t id);
...@@ -20,6 +28,11 @@ struct dlm_ls *dlm_find_lockspace_device(int minor); ...@@ -20,6 +28,11 @@ struct dlm_ls *dlm_find_lockspace_device(int minor);
void dlm_put_lockspace(struct dlm_ls *ls); void dlm_put_lockspace(struct dlm_ls *ls);
void dlm_stop_lockspaces(void); void dlm_stop_lockspaces(void);
void dlm_stop_lockspaces_check(void); void dlm_stop_lockspaces_check(void);
int dlm_new_user_lockspace(const char *name, const char *cluster,
uint32_t flags, int lvblen,
const struct dlm_lockspace_ops *ops,
void *ops_arg, int *ops_result,
dlm_lockspace_t **lockspace);
#endif /* __LOCKSPACE_DOT_H__ */ #endif /* __LOCKSPACE_DOT_H__ */
...@@ -1336,6 +1336,8 @@ struct dlm_msg *dlm_lowcomms_new_msg(int nodeid, int len, gfp_t allocation, ...@@ -1336,6 +1336,8 @@ struct dlm_msg *dlm_lowcomms_new_msg(int nodeid, int len, gfp_t allocation,
return NULL; return NULL;
} }
/* for dlm_lowcomms_commit_msg() */
kref_get(&msg->ref);
/* we assume if successful commit must called */ /* we assume if successful commit must called */
msg->idx = idx; msg->idx = idx;
return msg; return msg;
...@@ -1375,6 +1377,8 @@ void dlm_lowcomms_commit_msg(struct dlm_msg *msg) ...@@ -1375,6 +1377,8 @@ void dlm_lowcomms_commit_msg(struct dlm_msg *msg)
{ {
_dlm_lowcomms_commit_msg(msg); _dlm_lowcomms_commit_msg(msg);
srcu_read_unlock(&connections_srcu, msg->idx); srcu_read_unlock(&connections_srcu, msg->idx);
/* because dlm_lowcomms_new_msg() */
kref_put(&msg->ref, dlm_msg_release);
} }
#endif #endif
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
#include <trace/events/dlm.h>
#include "dlm_internal.h" #include "dlm_internal.h"
#include "lockspace.h" #include "lockspace.h"
#include "lock.h" #include "lock.h"
...@@ -184,7 +186,7 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode, ...@@ -184,7 +186,7 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode,
return; return;
ls = lkb->lkb_resource->res_ls; ls = lkb->lkb_resource->res_ls;
mutex_lock(&ls->ls_clear_proc_locks); spin_lock(&ls->ls_clear_proc_locks);
/* If ORPHAN/DEAD flag is set, it means the process is dead so an ast /* If ORPHAN/DEAD flag is set, it means the process is dead so an ast
can't be delivered. For ORPHAN's, dlm_clear_proc_locks() freed can't be delivered. For ORPHAN's, dlm_clear_proc_locks() freed
...@@ -230,7 +232,7 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode, ...@@ -230,7 +232,7 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode,
spin_unlock(&proc->locks_spin); spin_unlock(&proc->locks_spin);
} }
out: out:
mutex_unlock(&ls->ls_clear_proc_locks); spin_unlock(&ls->ls_clear_proc_locks);
} }
static int device_user_lock(struct dlm_user_proc *proc, static int device_user_lock(struct dlm_user_proc *proc,
...@@ -421,9 +423,9 @@ static int device_create_lockspace(struct dlm_lspace_params *params) ...@@ -421,9 +423,9 @@ static int device_create_lockspace(struct dlm_lspace_params *params)
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
error = dlm_new_lockspace(params->name, dlm_config.ci_cluster_name, params->flags, error = dlm_new_user_lockspace(params->name, dlm_config.ci_cluster_name,
DLM_USER_LVB_LEN, NULL, NULL, NULL, params->flags, DLM_USER_LVB_LEN, NULL,
&lockspace); NULL, NULL, &lockspace);
if (error) if (error)
return error; return error;
...@@ -882,7 +884,9 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, ...@@ -882,7 +884,9 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count,
goto try_another; goto try_another;
} }
if (cb.flags & DLM_CB_CAST) { if (cb.flags & DLM_CB_BAST) {
trace_dlm_bast(lkb->lkb_resource->res_ls, lkb, cb.mode);
} else if (cb.flags & DLM_CB_CAST) {
new_mode = cb.mode; new_mode = cb.mode;
if (!cb.sb_status && lkb->lkb_lksb->sb_lvbptr && if (!cb.sb_status && lkb->lkb_lksb->sb_lvbptr &&
...@@ -891,6 +895,7 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, ...@@ -891,6 +895,7 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count,
lkb->lkb_lksb->sb_status = cb.sb_status; lkb->lkb_lksb->sb_status = cb.sb_status;
lkb->lkb_lksb->sb_flags = cb.sb_flags; lkb->lkb_lksb->sb_flags = cb.sb_flags;
trace_dlm_ast(lkb->lkb_resource->res_ls, lkb);
} }
rv = copy_result_to_user(lkb->lkb_ua, rv = copy_result_to_user(lkb->lkb_ua,
......
...@@ -1302,7 +1302,7 @@ static int gdlm_mount(struct gfs2_sbd *sdp, const char *table) ...@@ -1302,7 +1302,7 @@ static int gdlm_mount(struct gfs2_sbd *sdp, const char *table)
memcpy(cluster, table, strlen(table) - strlen(fsname)); memcpy(cluster, table, strlen(table) - strlen(fsname));
fsname++; fsname++;
flags = DLM_LSFL_FS | DLM_LSFL_NEWEXCL; flags = DLM_LSFL_NEWEXCL;
/* /*
* create/join lockspace * create/join lockspace
......
...@@ -991,7 +991,7 @@ static int user_cluster_connect(struct ocfs2_cluster_connection *conn) ...@@ -991,7 +991,7 @@ static int user_cluster_connect(struct ocfs2_cluster_connection *conn)
lc->oc_type = NO_CONTROLD; lc->oc_type = NO_CONTROLD;
rc = dlm_new_lockspace(conn->cc_name, conn->cc_cluster_name, rc = dlm_new_lockspace(conn->cc_name, conn->cc_cluster_name,
DLM_LSFL_FS | DLM_LSFL_NEWEXCL, DLM_LVB_LEN, DLM_LSFL_NEWEXCL, DLM_LVB_LEN,
&ocfs2_ls_ops, conn, &ops_rv, &fsdlm); &ocfs2_ls_ops, conn, &ops_rv, &fsdlm);
if (rc) { if (rc) {
if (rc == -EEXIST || rc == -EPROTO) if (rc == -EEXIST || rc == -EPROTO)
......
...@@ -56,9 +56,6 @@ struct dlm_lockspace_ops { ...@@ -56,9 +56,6 @@ struct dlm_lockspace_ops {
* DLM_LSFL_TIMEWARN * DLM_LSFL_TIMEWARN
* The dlm should emit netlink messages if locks have been waiting * The dlm should emit netlink messages if locks have been waiting
* for a configurable amount of time. (Unused.) * for a configurable amount of time. (Unused.)
* DLM_LSFL_FS
* The lockspace user is in the kernel (i.e. filesystem). Enables
* direct bast/cast callbacks.
* DLM_LSFL_NEWEXCL * DLM_LSFL_NEWEXCL
* dlm_new_lockspace() should return -EEXIST if the lockspace exists. * dlm_new_lockspace() should return -EEXIST if the lockspace exists.
* *
...@@ -134,7 +131,7 @@ int dlm_lock(dlm_lockspace_t *lockspace, ...@@ -134,7 +131,7 @@ int dlm_lock(dlm_lockspace_t *lockspace,
int mode, int mode,
struct dlm_lksb *lksb, struct dlm_lksb *lksb,
uint32_t flags, uint32_t flags,
void *name, const void *name,
unsigned int namelen, unsigned int namelen,
uint32_t parent_lkid, uint32_t parent_lkid,
void (*lockast) (void *astarg), void (*lockast) (void *astarg),
......
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
/* note: we begin tracing dlm_lock_start() only if ls and lkb are found */ /* note: we begin tracing dlm_lock_start() only if ls and lkb are found */
TRACE_EVENT(dlm_lock_start, TRACE_EVENT(dlm_lock_start,
TP_PROTO(struct dlm_ls *ls, struct dlm_lkb *lkb, void *name, TP_PROTO(struct dlm_ls *ls, struct dlm_lkb *lkb, const void *name,
unsigned int namelen, int mode, __u32 flags), unsigned int namelen, int mode, __u32 flags),
TP_ARGS(ls, lkb, name, namelen, mode, flags), TP_ARGS(ls, lkb, name, namelen, mode, flags),
...@@ -91,10 +91,11 @@ TRACE_EVENT(dlm_lock_start, ...@@ -91,10 +91,11 @@ TRACE_EVENT(dlm_lock_start,
TRACE_EVENT(dlm_lock_end, TRACE_EVENT(dlm_lock_end,
TP_PROTO(struct dlm_ls *ls, struct dlm_lkb *lkb, void *name, TP_PROTO(struct dlm_ls *ls, struct dlm_lkb *lkb, const void *name,
unsigned int namelen, int mode, __u32 flags, int error), unsigned int namelen, int mode, __u32 flags, int error,
bool kernel_lock),
TP_ARGS(ls, lkb, name, namelen, mode, flags, error), TP_ARGS(ls, lkb, name, namelen, mode, flags, error, kernel_lock),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(__u32, ls_id) __field(__u32, ls_id)
...@@ -113,6 +114,7 @@ TRACE_EVENT(dlm_lock_end, ...@@ -113,6 +114,7 @@ TRACE_EVENT(dlm_lock_end,
__entry->lkb_id = lkb->lkb_id; __entry->lkb_id = lkb->lkb_id;
__entry->mode = mode; __entry->mode = mode;
__entry->flags = flags; __entry->flags = flags;
__entry->error = error;
r = lkb->lkb_resource; r = lkb->lkb_resource;
if (r) if (r)
...@@ -122,14 +124,14 @@ TRACE_EVENT(dlm_lock_end, ...@@ -122,14 +124,14 @@ TRACE_EVENT(dlm_lock_end,
memcpy(__get_dynamic_array(res_name), name, memcpy(__get_dynamic_array(res_name), name,
__get_dynamic_array_len(res_name)); __get_dynamic_array_len(res_name));
/* return value will be zeroed in those cases by dlm_lock() if (kernel_lock) {
* we do it here again to not introduce more overhead if /* return value will be zeroed in those cases by dlm_lock()
* trace isn't running and error reflects the return value. * we do it here again to not introduce more overhead if
*/ * trace isn't running and error reflects the return value.
if (error == -EAGAIN || error == -EDEADLK) */
__entry->error = 0; if (error == -EAGAIN || error == -EDEADLK)
else __entry->error = 0;
__entry->error = error; }
), ),
......
...@@ -69,7 +69,6 @@ struct dlm_lksb { ...@@ -69,7 +69,6 @@ struct dlm_lksb {
/* dlm_new_lockspace() flags */ /* dlm_new_lockspace() flags */
#define DLM_LSFL_TIMEWARN 0x00000002 #define DLM_LSFL_TIMEWARN 0x00000002
#define DLM_LSFL_FS 0x00000004
#define DLM_LSFL_NEWEXCL 0x00000008 #define DLM_LSFL_NEWEXCL 0x00000008
......
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