]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 May 2017 22:37:01 +0000 (15:37 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 May 2017 22:37:01 +0000 (15:37 -0700)
added patches:
asoc-intel-fix-pm-and-non-atomic-crash-in-bytcr-drivers.patch
handle-mismatched-open-calls.patch
timerfd-protect-the-might-cancel-mechanism-proper.patch

queue-4.4/asoc-intel-fix-pm-and-non-atomic-crash-in-bytcr-drivers.patch [new file with mode: 0644]
queue-4.4/handle-mismatched-open-calls.patch [new file with mode: 0644]
queue-4.4/timerfd-protect-the-might-cancel-mechanism-proper.patch [new file with mode: 0644]

diff --git a/queue-4.4/asoc-intel-fix-pm-and-non-atomic-crash-in-bytcr-drivers.patch b/queue-4.4/asoc-intel-fix-pm-and-non-atomic-crash-in-bytcr-drivers.patch
new file mode 100644 (file)
index 0000000..ed928e3
--- /dev/null
@@ -0,0 +1,70 @@
+From 6e4cac23c5a648d50b107d1b53e9c4e1120c7943 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 24 Apr 2017 14:09:55 +0200
+Subject: ASoC: intel: Fix PM and non-atomic crash in bytcr drivers
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 6e4cac23c5a648d50b107d1b53e9c4e1120c7943 upstream.
+
+The FE setups of Intel SST bytcr_rt5640 and bytcr_rt5651 drivers carry
+the ignore_suspend flag, and this prevents the suspend/resume working
+properly while the stream is running, since SST core code has the
+check of the running streams and returns -EBUSY.  Drop these
+superfluous flags for fixing the behavior.
+
+Also, the bytcr_rt5640 driver lacks of nonatomic flag in some FE
+definitions, which leads to the kernel Oops at suspend/resume like:
+
+  BUG: scheduling while atomic: systemd-sleep/3144/0x00000003
+  Call Trace:
+   dump_stack+0x5c/0x7a
+   __schedule_bug+0x55/0x70
+   __schedule+0x63c/0x8c0
+   schedule+0x3d/0x90
+   schedule_timeout+0x16b/0x320
+   ? del_timer_sync+0x50/0x50
+   ? sst_wait_timeout+0xa9/0x170 [snd_intel_sst_core]
+   ? sst_wait_timeout+0xa9/0x170 [snd_intel_sst_core]
+   ? remove_wait_queue+0x60/0x60
+   ? sst_prepare_and_post_msg+0x275/0x960 [snd_intel_sst_core]
+   ? sst_pause_stream+0x9b/0x110 [snd_intel_sst_core]
+   ....
+
+This patch addresses these appropriately, too.
+
+[tiwai: applied only to bytcr_rt5640 as bytcr_rt5651 isn't present in
+ 4.4.x yet]
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Acked-by: Vinod Koul <vinod.koul@intel.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Cc: <stable@vger.kernel.org> # v4.1+
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+
+This is the patch modified to be applicable to 4.4.x that failed in
+your previous queue.
+
+ sound/soc/intel/boards/bytcr_rt5640.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/intel/boards/bytcr_rt5640.c
++++ b/sound/soc/intel/boards/bytcr_rt5640.c
+@@ -139,7 +139,7 @@ static struct snd_soc_dai_link byt_daili
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .platform_name = "sst-mfld-platform",
+-              .ignore_suspend = 1,
++              .nonatomic = true,
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+@@ -166,6 +166,7 @@ static struct snd_soc_dai_link byt_daili
+                                               | SND_SOC_DAIFMT_CBS_CFS,
+               .be_hw_params_fixup = byt_codec_fixup,
+               .ignore_suspend = 1,
++              .nonatomic = true,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ops = &byt_be_ssp2_ops,
diff --git a/queue-4.4/handle-mismatched-open-calls.patch b/queue-4.4/handle-mismatched-open-calls.patch
new file mode 100644 (file)
index 0000000..b46b541
--- /dev/null
@@ -0,0 +1,335 @@
+From 38bd49064a1ecb67baad33598e3d824448ab11ec Mon Sep 17 00:00:00 2001
+From: Sachin Prabhu <sprabhu@redhat.com>
+Date: Fri, 3 Mar 2017 15:41:38 -0800
+Subject: Handle mismatched open calls
+
+From: Sachin Prabhu <sprabhu@redhat.com>
+
+commit 38bd49064a1ecb67baad33598e3d824448ab11ec upstream.
+
+A signal can interrupt a SendReceive call which result in incoming
+responses to the call being ignored. This is a problem for calls such as
+open which results in the successful response being ignored. This
+results in an open file resource on the server.
+
+The patch looks into responses which were cancelled after being sent and
+in case of successful open closes the open fids.
+
+For this patch, the check is only done in SendReceive2()
+
+RH-bz: 1403319
+
+Signed-off-by: Sachin Prabhu <sprabhu@redhat.com>
+Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
+Acked-by: Sachin Prabhu <sprabhu@redhat.com>
+Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/cifsglob.h      |   11 +++++++++
+ fs/cifs/cifssmb.c       |    4 +++
+ fs/cifs/connect.c       |   13 +++++++++-
+ fs/cifs/smb2misc.c      |   44 ++++++++++++++++++++++++++++++++++++
+ fs/cifs/smb2ops.c       |    4 +++
+ fs/cifs/smb2proto.h     |    7 +++++
+ fs/cifs/smb2transport.c |   58 +++++++++++++++++++++++++++++++++++++++++++-----
+ fs/cifs/transport.c     |    2 +
+ 8 files changed, 135 insertions(+), 8 deletions(-)
+
+--- a/fs/cifs/cifsglob.h
++++ b/fs/cifs/cifsglob.h
+@@ -227,6 +227,7 @@ struct smb_version_operations {
+       /* verify the message */
+       int (*check_message)(char *, unsigned int);
+       bool (*is_oplock_break)(char *, struct TCP_Server_Info *);
++      int (*handle_cancelled_mid)(char *, struct TCP_Server_Info *);
+       void (*downgrade_oplock)(struct TCP_Server_Info *,
+                                       struct cifsInodeInfo *, bool);
+       /* process transaction2 response */
+@@ -1289,12 +1290,19 @@ struct mid_q_entry {
+       void *callback_data;      /* general purpose pointer for callback */
+       void *resp_buf;         /* pointer to received SMB header */
+       int mid_state;  /* wish this were enum but can not pass to wait_event */
++      unsigned int mid_flags;
+       __le16 command;         /* smb command code */
+       bool large_buf:1;       /* if valid response, is pointer to large buf */
+       bool multiRsp:1;        /* multiple trans2 responses for one request  */
+       bool multiEnd:1;        /* both received */
+ };
++struct close_cancelled_open {
++      struct cifs_fid         fid;
++      struct cifs_tcon        *tcon;
++      struct work_struct      work;
++};
++
+ /*    Make code in transport.c a little cleaner by moving
+       update of optional stats into function below */
+ #ifdef CONFIG_CIFS_STATS2
+@@ -1426,6 +1434,9 @@ static inline void free_dfs_info_array(s
+ #define   MID_RESPONSE_MALFORMED 0x10
+ #define   MID_SHUTDOWN                 0x20
++/* Flags */
++#define   MID_WAIT_CANCELLED   1 /* Cancelled while waiting for response */
++
+ /* Types of response buffer returned from SendReceive2 */
+ #define   CIFS_NO_BUFFER        0    /* Response buffer not returned */
+ #define   CIFS_SMALL_BUFFER     1
+--- a/fs/cifs/cifssmb.c
++++ b/fs/cifs/cifssmb.c
+@@ -1424,6 +1424,8 @@ cifs_readv_discard(struct TCP_Server_Inf
+       length = discard_remaining_data(server);
+       dequeue_mid(mid, rdata->result);
++      mid->resp_buf = server->smallbuf;
++      server->smallbuf = NULL;
+       return length;
+ }
+@@ -1538,6 +1540,8 @@ cifs_readv_receive(struct TCP_Server_Inf
+               return cifs_readv_discard(server, mid);
+       dequeue_mid(mid, false);
++      mid->resp_buf = server->smallbuf;
++      server->smallbuf = NULL;
+       return length;
+ }
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -924,10 +924,19 @@ cifs_demultiplex_thread(void *p)
+               server->lstrp = jiffies;
+               if (mid_entry != NULL) {
++                      if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) &&
++                           mid_entry->mid_state == MID_RESPONSE_RECEIVED &&
++                                      server->ops->handle_cancelled_mid)
++                              server->ops->handle_cancelled_mid(
++                                                      mid_entry->resp_buf,
++                                                      server);
++
+                       if (!mid_entry->multiRsp || mid_entry->multiEnd)
+                               mid_entry->callback(mid_entry);
+-              } else if (!server->ops->is_oplock_break ||
+-                         !server->ops->is_oplock_break(buf, server)) {
++              } else if (server->ops->is_oplock_break &&
++                         server->ops->is_oplock_break(buf, server)) {
++                      cifs_dbg(FYI, "Received oplock break\n");
++              } else {
+                       cifs_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n",
+                                atomic_read(&midCount));
+                       cifs_dump_mem("Received Data is: ", buf,
+--- a/fs/cifs/smb2misc.c
++++ b/fs/cifs/smb2misc.c
+@@ -630,3 +630,47 @@ smb2_is_valid_oplock_break(char *buffer,
+       cifs_dbg(FYI, "Can not process oplock break for non-existent connection\n");
+       return false;
+ }
++
++void
++smb2_cancelled_close_fid(struct work_struct *work)
++{
++      struct close_cancelled_open *cancelled = container_of(work,
++                                      struct close_cancelled_open, work);
++
++      cifs_dbg(VFS, "Close unmatched open\n");
++
++      SMB2_close(0, cancelled->tcon, cancelled->fid.persistent_fid,
++                 cancelled->fid.volatile_fid);
++      cifs_put_tcon(cancelled->tcon);
++      kfree(cancelled);
++}
++
++int
++smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server)
++{
++      struct smb2_hdr *hdr = (struct smb2_hdr *)buffer;
++      struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)buffer;
++      struct cifs_tcon *tcon;
++      struct close_cancelled_open *cancelled;
++
++      if (hdr->Command != SMB2_CREATE || hdr->Status != STATUS_SUCCESS)
++              return 0;
++
++      cancelled = kzalloc(sizeof(*cancelled), GFP_KERNEL);
++      if (!cancelled)
++              return -ENOMEM;
++
++      tcon = smb2_find_smb_tcon(server, hdr->SessionId, hdr->TreeId);
++      if (!tcon) {
++              kfree(cancelled);
++              return -ENOENT;
++      }
++
++      cancelled->fid.persistent_fid = rsp->PersistentFileId;
++      cancelled->fid.volatile_fid = rsp->VolatileFileId;
++      cancelled->tcon = tcon;
++      INIT_WORK(&cancelled->work, smb2_cancelled_close_fid);
++      queue_work(cifsiod_wq, &cancelled->work);
++
++      return 0;
++}
+--- a/fs/cifs/smb2ops.c
++++ b/fs/cifs/smb2ops.c
+@@ -1511,6 +1511,7 @@ struct smb_version_operations smb20_oper
+       .clear_stats = smb2_clear_stats,
+       .print_stats = smb2_print_stats,
+       .is_oplock_break = smb2_is_valid_oplock_break,
++      .handle_cancelled_mid = smb2_handle_cancelled_mid,
+       .downgrade_oplock = smb2_downgrade_oplock,
+       .need_neg = smb2_need_neg,
+       .negotiate = smb2_negotiate,
+@@ -1589,6 +1590,7 @@ struct smb_version_operations smb21_oper
+       .clear_stats = smb2_clear_stats,
+       .print_stats = smb2_print_stats,
+       .is_oplock_break = smb2_is_valid_oplock_break,
++      .handle_cancelled_mid = smb2_handle_cancelled_mid,
+       .downgrade_oplock = smb2_downgrade_oplock,
+       .need_neg = smb2_need_neg,
+       .negotiate = smb2_negotiate,
+@@ -1670,6 +1672,7 @@ struct smb_version_operations smb30_oper
+       .print_stats = smb2_print_stats,
+       .dump_share_caps = smb2_dump_share_caps,
+       .is_oplock_break = smb2_is_valid_oplock_break,
++      .handle_cancelled_mid = smb2_handle_cancelled_mid,
+       .downgrade_oplock = smb2_downgrade_oplock,
+       .need_neg = smb2_need_neg,
+       .negotiate = smb2_negotiate,
+@@ -1757,6 +1760,7 @@ struct smb_version_operations smb311_ope
+       .print_stats = smb2_print_stats,
+       .dump_share_caps = smb2_dump_share_caps,
+       .is_oplock_break = smb2_is_valid_oplock_break,
++      .handle_cancelled_mid = smb2_handle_cancelled_mid,
+       .downgrade_oplock = smb2_downgrade_oplock,
+       .need_neg = smb2_need_neg,
+       .negotiate = smb2_negotiate,
+--- a/fs/cifs/smb2proto.h
++++ b/fs/cifs/smb2proto.h
+@@ -47,6 +47,10 @@ extern struct mid_q_entry *smb2_setup_re
+                             struct smb_rqst *rqst);
+ extern struct mid_q_entry *smb2_setup_async_request(
+                       struct TCP_Server_Info *server, struct smb_rqst *rqst);
++extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server,
++                                         __u64 ses_id);
++extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server,
++                                              __u64 ses_id, __u32  tid);
+ extern int smb2_calc_signature(struct smb_rqst *rqst,
+                               struct TCP_Server_Info *server);
+ extern int smb3_calc_signature(struct smb_rqst *rqst,
+@@ -157,6 +161,9 @@ extern int SMB2_set_compression(const un
+ extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
+                            const u64 persistent_fid, const u64 volatile_fid,
+                            const __u8 oplock_level);
++extern int smb2_handle_cancelled_mid(char *buffer,
++                                      struct TCP_Server_Info *server);
++void smb2_cancelled_close_fid(struct work_struct *work);
+ extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
+                        u64 persistent_file_id, u64 volatile_file_id,
+                        struct kstatfs *FSData);
+--- a/fs/cifs/smb2transport.c
++++ b/fs/cifs/smb2transport.c
+@@ -115,22 +115,68 @@ smb3_crypto_shash_allocate(struct TCP_Se
+ }
+ static struct cifs_ses *
+-smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server)
++smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id)
+ {
+       struct cifs_ses *ses;
+-      spin_lock(&cifs_tcp_ses_lock);
+       list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
+-              if (ses->Suid != smb2hdr->SessionId)
++              if (ses->Suid != ses_id)
+                       continue;
+-              spin_unlock(&cifs_tcp_ses_lock);
+               return ses;
+       }
++
++      return NULL;
++}
++
++struct cifs_ses *
++smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id)
++{
++      struct cifs_ses *ses;
++
++      spin_lock(&cifs_tcp_ses_lock);
++      ses = smb2_find_smb_ses_unlocked(server, ses_id);
+       spin_unlock(&cifs_tcp_ses_lock);
++      return ses;
++}
++
++static struct cifs_tcon *
++smb2_find_smb_sess_tcon_unlocked(struct cifs_ses *ses, __u32  tid)
++{
++      struct cifs_tcon *tcon;
++
++      list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
++              if (tcon->tid != tid)
++                      continue;
++              ++tcon->tc_count;
++              return tcon;
++      }
++
+       return NULL;
+ }
++/*
++ * Obtain tcon corresponding to the tid in the given
++ * cifs_ses
++ */
++
++struct cifs_tcon *
++smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid)
++{
++      struct cifs_ses *ses;
++      struct cifs_tcon *tcon;
++
++      spin_lock(&cifs_tcp_ses_lock);
++      ses = smb2_find_smb_ses_unlocked(server, ses_id);
++      if (!ses) {
++              spin_unlock(&cifs_tcp_ses_lock);
++              return NULL;
++      }
++      tcon = smb2_find_smb_sess_tcon_unlocked(ses, tid);
++      spin_unlock(&cifs_tcp_ses_lock);
++
++      return tcon;
++}
+ int
+ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
+@@ -143,7 +189,7 @@ smb2_calc_signature(struct smb_rqst *rqs
+       struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+       struct cifs_ses *ses;
+-      ses = smb2_find_smb_ses(smb2_pdu, server);
++      ses = smb2_find_smb_ses(server, smb2_pdu->SessionId);
+       if (!ses) {
+               cifs_dbg(VFS, "%s: Could not find session\n", __func__);
+               return 0;
+@@ -314,7 +360,7 @@ smb3_calc_signature(struct smb_rqst *rqs
+       struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+       struct cifs_ses *ses;
+-      ses = smb2_find_smb_ses(smb2_pdu, server);
++      ses = smb2_find_smb_ses(server, smb2_pdu->SessionId);
+       if (!ses) {
+               cifs_dbg(VFS, "%s: Could not find session\n", __func__);
+               return 0;
+--- a/fs/cifs/transport.c
++++ b/fs/cifs/transport.c
+@@ -786,9 +786,11 @@ SendReceive2(const unsigned int xid, str
+       rc = wait_for_response(ses->server, midQ);
+       if (rc != 0) {
++              cifs_dbg(FYI, "Cancelling wait for mid %llu\n", midQ->mid);
+               send_cancel(ses->server, buf, midQ);
+               spin_lock(&GlobalMid_Lock);
+               if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
++                      midQ->mid_flags |= MID_WAIT_CANCELLED;
+                       midQ->callback = DeleteMidQEntry;
+                       spin_unlock(&GlobalMid_Lock);
+                       cifs_small_buf_release(buf);
diff --git a/queue-4.4/timerfd-protect-the-might-cancel-mechanism-proper.patch b/queue-4.4/timerfd-protect-the-might-cancel-mechanism-proper.patch
new file mode 100644 (file)
index 0000000..deb74bb
--- /dev/null
@@ -0,0 +1,96 @@
+From 1e38da300e1e395a15048b0af1e5305bd91402f6 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Tue, 31 Jan 2017 15:24:03 +0100
+Subject: timerfd: Protect the might cancel mechanism proper
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+commit 1e38da300e1e395a15048b0af1e5305bd91402f6 upstream.
+
+The handling of the might_cancel queueing is not properly protected, so
+parallel operations on the file descriptor can race with each other and
+lead to list corruptions or use after free.
+
+Protect the context for these operations with a seperate lock.
+
+The wait queue lock cannot be reused for this because that would create a
+lock inversion scenario vs. the cancel lock. Replacing might_cancel with an
+atomic (atomic_t or atomic bit) does not help either because it still can
+race vs. the actual list operation.
+
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: "linux-fsdevel@vger.kernel.org"
+Cc: syzkaller <syzkaller@googlegroups.com>
+Cc: Al Viro <viro@zeniv.linux.org.uk>
+Cc: linux-fsdevel@vger.kernel.org
+Link: http://lkml.kernel.org/r/alpine.DEB.2.20.1701311521430.3457@nanos
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/timerfd.c |   17 ++++++++++++++---
+ 1 file changed, 14 insertions(+), 3 deletions(-)
+
+--- a/fs/timerfd.c
++++ b/fs/timerfd.c
+@@ -40,6 +40,7 @@ struct timerfd_ctx {
+       short unsigned settime_flags;   /* to show in fdinfo */
+       struct rcu_head rcu;
+       struct list_head clist;
++      spinlock_t cancel_lock;
+       bool might_cancel;
+ };
+@@ -112,7 +113,7 @@ void timerfd_clock_was_set(void)
+       rcu_read_unlock();
+ }
+-static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
++static void __timerfd_remove_cancel(struct timerfd_ctx *ctx)
+ {
+       if (ctx->might_cancel) {
+               ctx->might_cancel = false;
+@@ -122,6 +123,13 @@ static void timerfd_remove_cancel(struct
+       }
+ }
++static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
++{
++      spin_lock(&ctx->cancel_lock);
++      __timerfd_remove_cancel(ctx);
++      spin_unlock(&ctx->cancel_lock);
++}
++
+ static bool timerfd_canceled(struct timerfd_ctx *ctx)
+ {
+       if (!ctx->might_cancel || ctx->moffs.tv64 != KTIME_MAX)
+@@ -132,6 +140,7 @@ static bool timerfd_canceled(struct time
+ static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
+ {
++      spin_lock(&ctx->cancel_lock);
+       if ((ctx->clockid == CLOCK_REALTIME ||
+            ctx->clockid == CLOCK_REALTIME_ALARM) &&
+           (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
+@@ -141,9 +150,10 @@ static void timerfd_setup_cancel(struct
+                       list_add_rcu(&ctx->clist, &cancel_list);
+                       spin_unlock(&cancel_lock);
+               }
+-      } else if (ctx->might_cancel) {
+-              timerfd_remove_cancel(ctx);
++      } else {
++              __timerfd_remove_cancel(ctx);
+       }
++      spin_unlock(&ctx->cancel_lock);
+ }
+ static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
+@@ -395,6 +405,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clo
+               return -ENOMEM;
+       init_waitqueue_head(&ctx->wqh);
++      spin_lock_init(&ctx->cancel_lock);
+       ctx->clockid = clockid;
+       if (isalarm(ctx))