Skip to content

Commit a034c13

Browse files
Alexander Aringteigland
authored andcommitted
fs: dlm: fix DLM_IFL_CB_PENDING gets overwritten
This patch introduce a new internal flag per lkb value to handle internal flags which are handled not on wire. The current lkb internal flags stored as lkb->lkb_flags are split in upper and lower bits, the lower bits are used to share internal flags over wire for other cluster wide lkb copies on other nodes. In commit 61bed0b ("fs: dlm: use a non-static queue for callbacks") we introduced a new internal flag for pending callbacks for the dlm callback queue. This flag is protected by the lkb->lkb_cb_lock lock. This patch overlooked that on dlm receive path and the mentioned upper and lower bits, that dlm will read the flags, mask it and write it back. As example receive_flags() in fs/dlm/lock.c. This flag manipulation is not done atomically and is not protected by lkb->lkb_cb_lock. This has unknown side effects of the current callback handling. In future we should move to set/clear/test bit functionality and avoid read, mask and writing back flag values. In later patches we will move the upper parts to the new introduced internal lkb flags which are not shared between other cluster nodes to the new non shared internal flag field to avoid similar issues. Cc: stable@vger.kernel.org Fixes: 61bed0b ("fs: dlm: use a non-static queue for callbacks") Reported-by: Bob Peterson <rpeterso@redhat.com> Signed-off-by: Alexander Aring <aahringo@redhat.com> Signed-off-by: David Teigland <teigland@redhat.com>
1 parent fe15c26 commit a034c13

3 files changed

Lines changed: 9 additions & 7 deletions

File tree

fs/dlm/ast.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ void dlm_purge_lkb_callbacks(struct dlm_lkb *lkb)
4545
kref_put(&cb->ref, dlm_release_callback);
4646
}
4747

48-
lkb->lkb_flags &= ~DLM_IFL_CB_PENDING;
48+
clear_bit(DLM_IFL_CB_PENDING_BIT, &lkb->lkb_iflags);
4949

5050
/* invalidate */
5151
dlm_callback_set_last_ptr(&lkb->lkb_last_cast, NULL);
@@ -103,10 +103,9 @@ int dlm_enqueue_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
103103
cb->sb_status = status;
104104
cb->sb_flags = (sbflags & 0x000000FF);
105105
kref_init(&cb->ref);
106-
if (!(lkb->lkb_flags & DLM_IFL_CB_PENDING)) {
107-
lkb->lkb_flags |= DLM_IFL_CB_PENDING;
106+
if (!test_and_set_bit(DLM_IFL_CB_PENDING_BIT, &lkb->lkb_iflags))
108107
rv = DLM_ENQUEUE_CALLBACK_NEED_SCHED;
109-
}
108+
110109
list_add_tail(&cb->list, &lkb->lkb_callbacks);
111110

112111
if (flags & DLM_CB_CAST)
@@ -209,7 +208,7 @@ void dlm_callback_work(struct work_struct *work)
209208
spin_lock(&lkb->lkb_cb_lock);
210209
rv = dlm_dequeue_lkb_callback(lkb, &cb);
211210
if (rv == DLM_DEQUEUE_CALLBACK_EMPTY) {
212-
lkb->lkb_flags &= ~DLM_IFL_CB_PENDING;
211+
clear_bit(DLM_IFL_CB_PENDING_BIT, &lkb->lkb_iflags);
213212
spin_unlock(&lkb->lkb_cb_lock);
214213
break;
215214
}

fs/dlm/dlm_internal.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,9 @@ struct dlm_args {
211211
#endif
212212
#define DLM_IFL_DEADLOCK_CANCEL 0x01000000
213213
#define DLM_IFL_STUB_MS 0x02000000 /* magic number for m_flags */
214-
#define DLM_IFL_CB_PENDING 0x04000000
214+
215+
#define DLM_IFL_CB_PENDING_BIT 0
216+
215217
/* least significant 2 bytes are message changed, they are full transmitted
216218
* but at receive side only the 2 bytes LSB will be set.
217219
*
@@ -246,6 +248,7 @@ struct dlm_lkb {
246248
uint32_t lkb_exflags; /* external flags from caller */
247249
uint32_t lkb_sbflags; /* lksb flags */
248250
uint32_t lkb_flags; /* internal flags */
251+
unsigned long lkb_iflags; /* internal flags */
249252
uint32_t lkb_lvbseq; /* lvb sequence number */
250253

251254
int8_t lkb_status; /* granted, waiting, convert */

fs/dlm/user.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -884,7 +884,7 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count,
884884
goto try_another;
885885
case DLM_DEQUEUE_CALLBACK_LAST:
886886
list_del_init(&lkb->lkb_cb_list);
887-
lkb->lkb_flags &= ~DLM_IFL_CB_PENDING;
887+
clear_bit(DLM_IFL_CB_PENDING_BIT, &lkb->lkb_iflags);
888888
break;
889889
case DLM_DEQUEUE_CALLBACK_SUCCESS:
890890
break;

0 commit comments

Comments
 (0)