Print this page
NEX-4433 Deadlock among txg_wait_synced(), sbd_pgr_remove_it_handle(), and ppt_sess_lookup_create() after HA failover
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
NEX-3111 Comstar does not pass cstyle and hdrchk
        Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
        Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
        Reviewed by: Tony Nguyen <tony.nguyen@nexenta.com>
SUP-765 When a Windows Clustered Shared Volume is placed on a pool under Nexenta HA Cluster control the clustered shared disk looses its PGR3 reservation to the presented zvol.
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Tony Nguyen <tony.nguyen@nexenta.com>
Reviewed by: Josef Sipek <josef.sipek@nexenta.com>
Re #6790 backspace should perform delete on console
VAAI (XXX ATS support for COMSTAR, YYY Block-copy support for COMSTAR)

@@ -18,10 +18,12 @@
  *
  * CDDL HEADER END
  */
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #include <sys/atomic.h>
 #include <sys/conf.h>
 #include <sys/byteorder.h>

@@ -37,11 +39,11 @@
 #include "stmf_sbd.h"
 #include "sbd_impl.h"
 
 #define MAX_PGR_PARAM_LIST_LENGTH       (256 * 1024)
 
-int  sbd_pgr_reservation_conflict(scsi_task_t *);
+int  sbd_pgr_reservation_conflict(scsi_task_t *, struct sbd_lu *sl);
 void sbd_pgr_reset(sbd_lu_t *);
 void sbd_pgr_initialize_it(scsi_task_t *, sbd_it_data_t *);
 void sbd_handle_pgr_in_cmd(scsi_task_t *, stmf_data_buf_t *);
 void sbd_handle_pgr_out_cmd(scsi_task_t *, stmf_data_buf_t *);
 void sbd_handle_pgr_out_data(scsi_task_t *, stmf_data_buf_t *);

@@ -80,10 +82,11 @@
 static void sbd_pgr_do_unregister(sbd_lu_t *, sbd_it_data_t *, sbd_pgr_key_t *);
 static void sbd_pgr_do_release(sbd_lu_t *, sbd_it_data_t *, uint8_t);
 static void sbd_pgr_do_reserve(sbd_pgr_t *, sbd_pgr_key_t *, sbd_it_data_t *it,
         stmf_scsi_session_t *, scsi_cdb_prout_t *);
 
+static boolean_t sbd_pgr_should_save(sbd_lu_t *);
 extern sbd_status_t sbd_write_meta_section(sbd_lu_t *, sm_section_hdr_t *);
 extern sbd_status_t sbd_read_meta_section(sbd_lu_t *, sm_section_hdr_t **,
         uint16_t);
 extern void sbd_swap_section_hdr(sm_section_hdr_t *);
 extern void sbd_handle_short_write_transfers(scsi_task_t *task,

@@ -293,10 +296,26 @@
         ret = sbd_write_meta_section(slu, (sm_section_hdr_t *)spi);
         kmem_free(spi, sz);
         return (ret);
 }
 
+/*
+ * Evaluate common cases where a PERSISTENT RESERVE OUT CDB handler should call
+ * sbd_pgr_meta_write().
+ */
+static boolean_t
+sbd_pgr_should_save(sbd_lu_t *slu)
+{
+        sbd_pgr_t               *pgr = slu->sl_pgr;
+
+        if (stmf_is_pgr_aptpl_always() == B_TRUE ||
+            (pgr->pgr_flags & (SBD_PGR_APTPL)))
+                return (B_TRUE);
+        else
+                return (B_FALSE);
+}
+
 sbd_status_t
 sbd_pgr_meta_load(sbd_lu_t *slu)
 {
         sbd_pgr_t               *pgr = slu->sl_pgr;
         sbd_pgr_info_t          *spi = NULL;

@@ -321,11 +340,16 @@
         if (spi->pgr_data_order != SMS_DATA_ORDER) {
                 sbd_swap_pgr_info(spi);
         }
 
         pgr->pgr_flags = spi->pgr_flags;
-        if (pgr->pgr_flags & SBD_PGR_APTPL) {
+        /*
+         * We reload APTPL reservations when:
+         *  1. Global override is enabled
+         *  2. APTPL was explicitly asserted in the PERSISTENT RESERVE OUT CDB
+         */
+        if (stmf_is_pgr_aptpl_always() || (pgr->pgr_flags & SBD_PGR_APTPL)) {
                 pgr->pgr_rsv_type = spi->pgr_rsv_type;
                 pgr->pgr_rsv_scope = spi->pgr_rsv_scope;
         } else {
                 PGR_CLEAR_RSV_FLAG(pgr->pgr_flags);
         }

@@ -411,10 +435,11 @@
 
         kmem_free(spi, spi->pgr_sms_header.sms_size);
         return (ret);
 
 sbd_pgr_meta_load_failed:
+        /* CSTYLED */
         {
         char *lun_name = sbd_get_devid_string(slu);
         sbd_pgr_keylist_dealloc(slu);
         kmem_free(spi, spi->pgr_sms_header.sms_size);
         cmn_err(CE_WARN, "sbd_pgr_meta_load: Failed to load PGR meta data "

@@ -434,11 +459,11 @@
         sbd_status_t            ret = SBD_SUCCESS;
         uint32_t                sz, totalsz;
 
         /* Calculate total pgr meta section size needed */
         sz = sizeof (sbd_pgr_info_t);
-        if (pgr->pgr_flags & SBD_PGR_APTPL) {
+        if ((pgr->pgr_flags & SBD_PGR_APTPL) || stmf_is_pgr_aptpl_always()) {
                 key = pgr->pgr_keylist;
                 while (key != NULL) {
                         sz = ALIGNED_TO_8BYTE_BOUNDARY(sz +
                             sizeof (sbd_pgr_key_info_t) - 1 +
                             key->pgr_key_lpt_len + key->pgr_key_rpt_len);

@@ -456,11 +481,11 @@
 
         spi->pgr_sms_header.sms_size = totalsz;
         spi->pgr_sms_header.sms_id = SMS_ID_PGR_INFO;
         spi->pgr_sms_header.sms_data_order = SMS_DATA_ORDER;
 
-        if (pgr->pgr_flags & SBD_PGR_APTPL) {
+        if ((pgr->pgr_flags & SBD_PGR_APTPL) || stmf_is_pgr_aptpl_always()) {
                 uint8_t *ptr;
                 key = pgr->pgr_keylist;
                 sz = sizeof (sbd_pgr_info_t);
                 while (key != NULL) {
                         spi_key = (sbd_pgr_key_info_t *)((uint8_t *)spi + sz);

@@ -482,12 +507,16 @@
                             sizeof (sbd_pgr_key_info_t) - 1 +
                             key->pgr_key_lpt_len + key->pgr_key_rpt_len);
                         key = key->pgr_key_next;
                 }
         }
-
+        rw_downgrade(&pgr->pgr_lock);
         ret = sbd_write_meta_section(slu, (sm_section_hdr_t *)spi);
+        if (!rw_tryupgrade(&pgr->pgr_lock)) {
+                rw_exit(&pgr->pgr_lock);
+                rw_enter(&pgr->pgr_lock, RW_WRITER);
+        }
         kmem_free(spi, totalsz);
         if (ret != SBD_SUCCESS) {
                 sbd_pgr_key_t   *tmp_list;
                 tmp_list = pgr->pgr_keylist;
                 pgr->pgr_keylist = NULL;

@@ -576,11 +605,12 @@
 sbd_pgr_reset(sbd_lu_t *slu)
 {
         sbd_pgr_t       *pgr  = slu->sl_pgr;
 
         rw_enter(&pgr->pgr_lock, RW_WRITER);
-        if (!(pgr->pgr_flags & SBD_PGR_APTPL)) {
+        if (!(pgr->pgr_flags & SBD_PGR_APTPL) &&
+            stmf_is_pgr_aptpl_always() == B_FALSE) {
                 sbd_pgr_keylist_dealloc(slu);
                 pgr->pgr_PRgeneration   = 0;
                 pgr->pgr_rsvholder      = NULL;
                 pgr->pgr_rsv_type       = 0;
                 pgr->pgr_flags          = 0;

@@ -810,13 +840,12 @@
 
 /*
  * Check for any PGR Reservation conflict. return 0 if access allowed
  */
 int
-sbd_pgr_reservation_conflict(scsi_task_t *task)
+sbd_pgr_reservation_conflict(scsi_task_t *task, sbd_lu_t *slu)
 {
-        sbd_lu_t        *slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
         sbd_pgr_t       *pgr = slu->sl_pgr;
         sbd_it_data_t   *it  = (sbd_it_data_t *)task->task_lu_itl_handle;
 
         /* If Registered */
         if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS && it->pgr_key_ptr)

@@ -1384,11 +1413,11 @@
 
         (void) sbd_pgr_do_register(slu, it, lpt, &rport, keyflag, svc_key);
 
 sbd_pgr_reg_done:
 
-        if (pgr->pgr_flags & SBD_PGR_APTPL || plist->aptpl) {
+        if (plist->aptpl || (sbd_pgr_should_save(slu) == B_TRUE)) {
                 if (plist->aptpl)
                         PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
                 else
                         PGR_CLEAR_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
 

@@ -1489,11 +1518,11 @@
 
                 }
         /* In case there is no reservation exist */
         } else {
                 sbd_pgr_do_reserve(pgr, key, it, ses, pr_out);
-                if (pgr->pgr_flags & SBD_PGR_APTPL) {
+                if (sbd_pgr_should_save(slu) == B_TRUE) {
                         if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
                                 stmf_scsilib_send_status(task, STATUS_CHECK,
                                     STMF_SAA_INSUFFICIENT_REG_RESOURCES);
                                 return;
                         }

@@ -1546,10 +1575,15 @@
         sbd_pgr_t               *pgr    = slu->sl_pgr;
         sbd_pgr_key_t           *key    = it->pgr_key_ptr;
 
         ASSERT(key);
 
+        /*
+         * XXX this does not honor APTPL
+         * (i.e., changes made to a formerly-persistent reservation are not
+         *  updated here!!!)
+         */
         if (SBD_PGR_RSVD(pgr)) {
                 if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS ||
                     pgr->pgr_rsvholder == key) {
                         if (pgr->pgr_rsv_type != pr_out->type ||
                             pgr->pgr_rsv_scope != pr_out->scope) {

@@ -1557,12 +1591,33 @@
                                     STMF_SAA_INVALID_RELEASE_OF_PR);
                                 return;
                         }
                         sbd_pgr_do_release(slu, it,
                             SBD_UA_RESERVATIONS_RELEASED);
+
+                        /*
+                         * XXX T10 SPC-3 5.6.10.2 says nothing about what to
+                         * do in the event of a failure updating the
+                         * PGR nvram store for a reservation associated with
+                         * an APTPL-enabled (see SPC-3 5.6.4.1) I_T
+                         * registration during a RELEASE service action.
+                         *
+                         * Technically, the CDB completed successfully, as per
+                         * the spec, but at some point we may need to enter
+                         * a recovery mode on the initiator(s) if we power cycle
+                         * the target at the wrong instant...
+                         */
+                        if (sbd_pgr_should_save(slu) == B_TRUE) {
+                                if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
+                                        stmf_scsilib_send_status(task,
+                                            STATUS_CHECK, /* CSTYLED */
+                                            STMF_SAA_INSUFFICIENT_REG_RESOURCES);
+                                        return;
                 }
         }
+                }
+        }
         stmf_scsilib_send_status(task, STATUS_GOOD, 0);
 }
 
 static void
 sbd_pgr_do_release(sbd_lu_t *slu, sbd_it_data_t *it, uint8_t ua_condition)

@@ -1600,11 +1655,11 @@
                 it->pgr_key_ptr = NULL;
         }
         mutex_exit(&slu->sl_lock);
         sbd_pgr_keylist_dealloc(slu);
         sbd_pgr_set_ua_conditions(slu, it, SBD_UA_RESERVATIONS_PREEMPTED);
-        if (pgr->pgr_flags & SBD_PGR_APTPL) {
+        if (sbd_pgr_should_save(slu) == B_TRUE) {
                 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
                         stmf_scsilib_send_status(task, STATUS_CHECK,
                             STMF_SAA_INSUFFICIENT_REG_RESOURCES);
                         return;
                 }

@@ -1715,11 +1770,11 @@
                                 return;
                         }
                 }
         }
 
-        if (pgr->pgr_flags & SBD_PGR_APTPL) {
+        if (sbd_pgr_should_save(slu) == B_TRUE) {
                 if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
                         stmf_scsilib_send_status(task, STATUS_CHECK,
                             STMF_SAA_INSUFFICIENT_REG_RESOURCES);
                         return;
                 }

@@ -1829,12 +1884,12 @@
         if (plist->unreg) {
                 sbd_pgr_do_unregister(slu, it, key);
         }
 
 
-        /* Write to disk if currenty aptpl is set or given task is setting it */
-        if (pgr->pgr_flags & SBD_PGR_APTPL || plist->aptpl) {
+        /* Write to disk if aptpl is currently set or this task is setting it */
+        if (plist->aptpl || (sbd_pgr_should_save(slu) == B_TRUE)) {
                 if (plist->aptpl)
                         PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
                 else
                         PGR_CLEAR_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);