Merge branch 'for-2.6.37/drivers' into for-linus
authorJens Axboe <jaxboe@fusionio.com>
Wed, 10 Nov 2010 13:51:27 +0000 (14:51 +0100)
committerJens Axboe <jaxboe@fusionio.com>
Wed, 10 Nov 2010 13:51:27 +0000 (14:51 +0100)
Conflicts:
drivers/block/cciss.c

Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
1  2 
drivers/block/cciss.c
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c

diff --combined drivers/block/cciss.c
@@@ -113,6 -113,8 +113,8 @@@ static struct board_type products[] = 
        {0x409D0E11, "Smart Array 6400 EM", &SA5_access},
        {0x40910E11, "Smart Array 6i", &SA5_access},
        {0x3225103C, "Smart Array P600", &SA5_access},
+       {0x3223103C, "Smart Array P800", &SA5_access},
+       {0x3234103C, "Smart Array P400", &SA5_access},
        {0x3235103C, "Smart Array P400i", &SA5_access},
        {0x3211103C, "Smart Array E200i", &SA5_access},
        {0x3212103C, "Smart Array E200", &SA5_access},
        {0x3214103C, "Smart Array E200i", &SA5_access},
        {0x3215103C, "Smart Array E200i", &SA5_access},
        {0x3237103C, "Smart Array E500", &SA5_access},
 -      {0x323d103c, "Smart Array P700M", &SA5_access},
 +      {0x3223103C, "Smart Array P800", &SA5_access},
 +      {0x3234103C, "Smart Array P400", &SA5_access},
 +      {0x323D103C, "Smart Array P700m", &SA5_access},
  };
  
  /* How long to wait (in milliseconds) for board to go into simple mode */
@@@ -1151,7 -1151,6 +1153,7 @@@ static int cciss_ioctl32_big_passthru(s
        int err;
        u32 cp;
  
 +      memset(&arg64, 0, sizeof(arg64));
        err = 0;
        err |=
            copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
@@@ -3753,7 -3752,7 +3755,7 @@@ static void __devinit cciss_wait_for_mo
        for (i = 0; i < MAX_CONFIG_WAIT; i++) {
                if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
                        break;
-               msleep(10);
+               usleep_range(10000, 20000);
        }
  }
  
@@@ -3937,10 -3936,9 +3939,9 @@@ static int __devinit cciss_lookup_board
        *board_id = ((subsystem_device_id << 16) & 0xffff0000) |
                        subsystem_vendor_id;
  
-       for (i = 0; i < ARRAY_SIZE(products); i++) {
+       for (i = 0; i < ARRAY_SIZE(products); i++)
                if (*board_id == products[i].board_id)
                        return i;
-       }
        dev_warn(&pdev->dev, "unrecognized board ID: 0x%08x, ignoring.\n",
                *board_id);
        return -ENODEV;
@@@ -3971,18 -3969,31 +3972,31 @@@ static int __devinit cciss_pci_find_mem
        return -ENODEV;
  }
  
- static int __devinit cciss_wait_for_board_ready(ctlr_info_t *h)
+ static int __devinit cciss_wait_for_board_state(struct pci_dev *pdev,
+       void __iomem *vaddr, int wait_for_ready)
+ #define BOARD_READY 1
+ #define BOARD_NOT_READY 0
  {
-       int i;
+       int i, iterations;
        u32 scratchpad;
  
-       for (i = 0; i < CCISS_BOARD_READY_ITERATIONS; i++) {
-               scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
-               if (scratchpad == CCISS_FIRMWARE_READY)
-                       return 0;
+       if (wait_for_ready)
+               iterations = CCISS_BOARD_READY_ITERATIONS;
+       else
+               iterations = CCISS_BOARD_NOT_READY_ITERATIONS;
+       for (i = 0; i < iterations; i++) {
+               scratchpad = readl(vaddr + SA5_SCRATCHPAD_OFFSET);
+               if (wait_for_ready) {
+                       if (scratchpad == CCISS_FIRMWARE_READY)
+                               return 0;
+               } else {
+                       if (scratchpad != CCISS_FIRMWARE_READY)
+                               return 0;
+               }
                msleep(CCISS_BOARD_READY_POLL_INTERVAL_MSECS);
        }
-       dev_warn(&h->pdev->dev, "board not ready, timed out.\n");
+       dev_warn(&pdev->dev, "board not ready, timed out.\n");
        return -ENODEV;
  }
  
@@@ -4031,6 -4042,11 +4045,11 @@@ static int __devinit cciss_find_cfgtabl
  static void __devinit cciss_get_max_perf_mode_cmds(struct ctlr_info *h)
  {
        h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
+       /* Limit commands in memory limited kdump scenario. */
+       if (reset_devices && h->max_commands > 32)
+               h->max_commands = 32;
        if (h->max_commands < 16) {
                dev_warn(&h->pdev->dev, "Controller reports "
                        "max supported commands of %d, an obvious lie. "
@@@ -4148,7 -4164,7 +4167,7 @@@ static int __devinit cciss_pci_init(ctl
                err = -ENOMEM;
                goto err_out_free_res;
        }
-       err = cciss_wait_for_board_ready(h);
+       err = cciss_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY);
        if (err)
                goto err_out_free_res;
        err = cciss_find_cfgtables(h);
@@@ -4313,36 -4329,6 +4332,6 @@@ static __devinit int cciss_message(stru
  #define cciss_soft_reset_controller(p) cciss_message(p, 1, 0)
  #define cciss_noop(p) cciss_message(p, 3, 0)
  
- static __devinit int cciss_reset_msi(struct pci_dev *pdev)
- {
- /* the #defines are stolen from drivers/pci/msi.h. */
- #define msi_control_reg(base)         (base + PCI_MSI_FLAGS)
- #define PCI_MSIX_FLAGS_ENABLE         (1 << 15)
-       int pos;
-       u16 control = 0;
-       pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
-       if (pos) {
-               pci_read_config_word(pdev, msi_control_reg(pos), &control);
-               if (control & PCI_MSI_FLAGS_ENABLE) {
-                       dev_info(&pdev->dev, "resetting MSI\n");
-                       pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSI_FLAGS_ENABLE);
-               }
-       }
-       pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
-       if (pos) {
-               pci_read_config_word(pdev, msi_control_reg(pos), &control);
-               if (control & PCI_MSIX_FLAGS_ENABLE) {
-                       dev_info(&pdev->dev, "resetting MSI-X\n");
-                       pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSIX_FLAGS_ENABLE);
-               }
-       }
-       return 0;
- }
  static int cciss_controller_hard_reset(struct pci_dev *pdev,
        void * __iomem vaddr, bool use_doorbell)
  {
   * states or using the doorbell register. */
  static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
  {
-       u16 saved_config_space[32];
        u64 cfg_offset;
        u32 cfg_base_addr;
        u64 cfg_base_addr_index;
        void __iomem *vaddr;
        unsigned long paddr;
        u32 misc_fw_support, active_transport;
-       int rc, i;
+       int rc;
        CfgTable_struct __iomem *cfgtable;
        bool use_doorbell;
        u32 board_id;
+       u16 command_register;
  
        /* For controllers as old a the p600, this is very nearly
         * the same thing as
         * pci_set_power_state(pci_dev, PCI_D0);
         * pci_restore_state(pci_dev);
         *
-        * but we can't use these nice canned kernel routines on
-        * kexec, because they also check the MSI/MSI-X state in PCI
-        * configuration space and do the wrong thing when it is
-        * set/cleared.  Also, the pci_save/restore_state functions
-        * violate the ordering requirements for restoring the
-        * configuration space from the CCISS document (see the
-        * comment below).  So we roll our own ....
-        *
         * For controllers newer than the P600, the pci power state
         * method of resetting doesn't work so we have another way
         * using the doorbell register.
                return -ENODEV;
        }
  
-       for (i = 0; i < 32; i++)
-               pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
+       /* Save the PCI command register */
+       pci_read_config_word(pdev, 4, &command_register);
+       /* Turn the board off.  This is so that later pci_restore_state()
+        * won't turn the board on before the rest of config space is ready.
+        */
+       pci_disable_device(pdev);
+       pci_save_state(pdev);
  
        /* find the first memory BAR, so we can find the cfg table */
        rc = cciss_pci_find_memory_BAR(pdev, &paddr);
        rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell);
        if (rc)
                goto unmap_cfgtable;
-       /* Restore the PCI configuration space.  The Open CISS
-        * Specification says, "Restore the PCI Configuration
-        * Registers, offsets 00h through 60h. It is important to
-        * restore the command register, 16-bits at offset 04h,
-        * last. Do not restore the configuration status register,
-        * 16-bits at offset 06h."  Note that the offset is 2*i.
-        */
-       for (i = 0; i < 32; i++) {
-               if (i == 2 || i == 3)
-                       continue;
-               pci_write_config_word(pdev, 2*i, saved_config_space[i]);
+       pci_restore_state(pdev);
+       rc = pci_enable_device(pdev);
+       if (rc) {
+               dev_warn(&pdev->dev, "failed to enable device.\n");
+               goto unmap_cfgtable;
        }
-       wmb();
-       pci_write_config_word(pdev, 4, saved_config_space[2]);
+       pci_write_config_word(pdev, 4, command_register);
  
        /* Some devices (notably the HP Smart Array 5i Controller)
           need a little pause here */
        msleep(CCISS_POST_RESET_PAUSE_MSECS);
  
+       /* Wait for board to become not ready, then ready. */
+       dev_info(&pdev->dev, "Waiting for board to become ready.\n");
+       rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY);
+       if (rc) /* Don't bail, might be E500, etc. which can't be reset */
+               dev_warn(&pdev->dev,
+                       "failed waiting for board to become not ready\n");
+       rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_READY);
+       if (rc) {
+               dev_warn(&pdev->dev,
+                       "failed waiting for board to become ready\n");
+               goto unmap_cfgtable;
+       }
+       dev_info(&pdev->dev, "board ready.\n");
        /* Controller should be in simple mode at this point.  If it's not,
         * It means we're on one of those controllers which doesn't support
         * the doorbell reset method and on which the PCI power management reset
@@@ -4539,8 -4528,6 +4531,6 @@@ static __devinit int cciss_init_reset_d
                return 0; /* just try to do the kdump anyhow. */
        if (rc)
                return -ENODEV;
-       if (cciss_reset_msi(pdev))
-               return -ENODEV;
  
        /* Now try to get the controller to respond to a no-op */
        for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) {
@@@ -4936,8 -4923,7 +4926,8 @@@ static void __exit cciss_cleanup(void
                }
        }
        kthread_stop(cciss_scan_thread);
 -      remove_proc_entry("driver/cciss", NULL);
 +      if (proc_cciss)
 +              remove_proc_entry("driver/cciss", NULL);
        bus_unregister(&cciss_bus_type);
  }
  
@@@ -114,11 -114,11 +114,11 @@@ struct drbd_conf
  #define D_ASSERT(exp) if (!(exp)) \
         dev_err(DEV, "ASSERT( " #exp " ) in %s:%d\n", __FILE__, __LINE__)
  
- #define ERR_IF(exp) if (({                            \
-       int _b = (exp) != 0;                            \
-       if (_b) dev_err(DEV, "%s: (%s) in %s:%d\n",     \
-               __func__, #exp, __FILE__, __LINE__);    \
-        _b;                                            \
+ #define ERR_IF(exp) if (({                                            \
+       int _b = (exp) != 0;                                            \
+       if (_b) dev_err(DEV, "ASSERT FAILED: %s: (%s) in %s:%d\n",      \
+                       __func__, #exp, __FILE__, __LINE__);            \
+       _b;                                                             \
        }))
  
  /* Defines to control fault insertion */
@@@ -749,17 -749,12 +749,12 @@@ struct drbd_epoch 
  
  /* drbd_epoch flag bits */
  enum {
-       DE_BARRIER_IN_NEXT_EPOCH_ISSUED,
-       DE_BARRIER_IN_NEXT_EPOCH_DONE,
-       DE_CONTAINS_A_BARRIER,
        DE_HAVE_BARRIER_NUMBER,
-       DE_IS_FINISHING,
  };
  
  enum epoch_event {
        EV_PUT,
        EV_GOT_BARRIER_NR,
-       EV_BARRIER_DONE,
        EV_BECAME_LAST,
        EV_CLEANUP = 32, /* used as flag */
  };
@@@ -801,11 -796,6 +796,6 @@@ enum 
        __EE_CALL_AL_COMPLETE_IO,
        __EE_MAY_SET_IN_SYNC,
  
-       /* This epoch entry closes an epoch using a barrier.
-        * On sucessful completion, the epoch is released,
-        * and the P_BARRIER_ACK send. */
-       __EE_IS_BARRIER,
        /* In case a barrier failed,
         * we need to resubmit without the barrier flag. */
        __EE_RESUBMITTED,
  };
  #define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO)
  #define EE_MAY_SET_IN_SYNC     (1<<__EE_MAY_SET_IN_SYNC)
- #define EE_IS_BARRIER          (1<<__EE_IS_BARRIER)
  #define       EE_RESUBMITTED         (1<<__EE_RESUBMITTED)
  #define EE_WAS_ERROR           (1<<__EE_WAS_ERROR)
  #define EE_HAS_DIGEST          (1<<__EE_HAS_DIGEST)
@@@ -843,16 -832,15 +832,15 @@@ enum 
                                 * Gets cleared when the state.conn
                                 * goes into C_CONNECTED state. */
        WRITE_BM_AFTER_RESYNC,  /* A kmalloc() during resync failed */
-       NO_BARRIER_SUPP,        /* underlying block device doesn't implement barriers */
        CONSIDER_RESYNC,
  
-       MD_NO_BARRIER,          /* meta data device does not support barriers,
-                                  so don't even try */
+       MD_NO_FUA,              /* Users wants us to not use FUA/FLUSH on meta data dev */
        SUSPEND_IO,             /* suspend application io */
        BITMAP_IO,              /* suspend application io;
                                   once no more io in flight, start bitmap io */
        BITMAP_IO_QUEUED,       /* Started bitmap IO */
-       GO_DISKLESS,            /* Disk failed, local_cnt reached zero, we are going diskless */
+       GO_DISKLESS,            /* Disk is being detached, on io-error or admin request. */
+       WAS_IO_ERROR,           /* Local disk failed returned IO error */
        RESYNC_AFTER_NEG,       /* Resync after online grow after the attach&negotiate finished. */
        NET_CONGESTED,          /* The data socket is congested */
  
@@@ -947,7 -935,6 +935,6 @@@ enum write_ordering_e 
        WO_none,
        WO_drain_io,
        WO_bdev_flush,
-       WO_bio_barrier
  };
  
  struct fifo_buffer {
@@@ -1281,6 -1268,7 +1268,7 @@@ extern int drbd_bmio_set_n_write(struc
  extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev);
  extern int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why);
  extern void drbd_go_diskless(struct drbd_conf *mdev);
+ extern void drbd_ldev_destroy(struct drbd_conf *mdev);
  
  
  /* Meta data layout
@@@ -1798,17 -1786,17 +1786,17 @@@ static inline void __drbd_chk_io_error_
        case EP_PASS_ON:
                if (!forcedetach) {
                        if (__ratelimit(&drbd_ratelimit_state))
-                               dev_err(DEV, "Local IO failed in %s."
-                                            "Passing error on...\n", where);
+                               dev_err(DEV, "Local IO failed in %s.\n", where);
                        break;
                }
                /* NOTE fall through to detach case if forcedetach set */
        case EP_DETACH:
        case EP_CALL_HELPER:
+               set_bit(WAS_IO_ERROR, &mdev->flags);
                if (mdev->state.disk > D_FAILED) {
                        _drbd_set_state(_NS(mdev, disk, D_FAILED), CS_HARD, NULL);
-                       dev_err(DEV, "Local IO failed in %s."
-                                    "Detaching...\n", where);
+                       dev_err(DEV,
+                               "Local IO failed in %s. Detaching...\n", where);
                }
                break;
        }
@@@ -1874,7 -1862,7 +1862,7 @@@ static inline sector_t drbd_md_last_sec
  static inline sector_t drbd_get_capacity(struct block_device *bdev)
  {
        /* return bdev ? get_capacity(bdev->bd_disk) : 0; */
 -      return bdev ? bdev->bd_inode->i_size >> 9 : 0;
 +      return bdev ? i_size_read(bdev->bd_inode) >> 9 : 0;
  }
  
  /**
@@@ -2127,7 -2115,11 +2115,11 @@@ static inline void put_ldev(struct drbd
        __release(local);
        D_ASSERT(i >= 0);
        if (i == 0) {
+               if (mdev->state.disk == D_DISKLESS)
+                       /* even internal references gone, safe to destroy */
+                       drbd_ldev_destroy(mdev);
                if (mdev->state.disk == D_FAILED)
+                       /* all application IO references gone. */
                        drbd_go_diskless(mdev);
                wake_up(&mdev->misc_wait);
        }
@@@ -2138,6 -2130,10 +2130,10 @@@ static inline int _get_ldev_if_state(st
  {
        int io_allowed;
  
+       /* never get a reference while D_DISKLESS */
+       if (mdev->state.disk == D_DISKLESS)
+               return 0;
        atomic_inc(&mdev->local_cnt);
        io_allowed = (mdev->state.disk >= mins);
        if (!io_allowed)
@@@ -2406,12 -2402,12 +2402,12 @@@ static inline void drbd_md_flush(struc
  {
        int r;
  
-       if (test_bit(MD_NO_BARRIER, &mdev->flags))
+       if (test_bit(MD_NO_FUA, &mdev->flags))
                return;
  
        r = blkdev_issue_flush(mdev->ldev->md_bdev, GFP_KERNEL, NULL);
        if (r) {
-               set_bit(MD_NO_BARRIER, &mdev->flags);
+               set_bit(MD_NO_FUA, &mdev->flags);
                dev_err(DEV, "meta data flush failed with status %d, disabling md-flushes\n", r);
        }
  }
@@@ -835,6 -835,15 +835,15 @@@ static union drbd_state sanitize_state(
            ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING && ns.conn <= C_TEAR_DOWN)
                ns.conn = os.conn;
  
+       /* we cannot fail (again) if we already detached */
+       if (ns.disk == D_FAILED && os.disk == D_DISKLESS)
+               ns.disk = D_DISKLESS;
+       /* if we are only D_ATTACHING yet,
+        * we can (and should) go directly to D_DISKLESS. */
+       if (ns.disk == D_FAILED && os.disk == D_ATTACHING)
+               ns.disk = D_DISKLESS;
        /* After C_DISCONNECTING only C_STANDALONE may follow */
        if (os.conn == C_DISCONNECTING && ns.conn != C_STANDALONE)
                ns.conn = os.conn;
@@@ -1056,7 -1065,15 +1065,15 @@@ int __drbd_set_state(struct drbd_conf *
            !test_and_set_bit(CONFIG_PENDING, &mdev->flags))
                set_bit(DEVICE_DYING, &mdev->flags);
  
-       mdev->state.i = ns.i;
+       /* if we are going -> D_FAILED or D_DISKLESS, grab one extra reference
+        * on the ldev here, to be sure the transition -> D_DISKLESS resp.
+        * drbd_ldev_destroy() won't happen before our corresponding
+        * after_state_ch works run, where we put_ldev again. */
+       if ((os.disk != D_FAILED && ns.disk == D_FAILED) ||
+           (os.disk != D_DISKLESS && ns.disk == D_DISKLESS))
+               atomic_inc(&mdev->local_cnt);
+       mdev->state = ns;
        wake_up(&mdev->misc_wait);
        wake_up(&mdev->state_wait);
  
@@@ -1268,7 -1285,6 +1285,6 @@@ static void after_state_ch(struct drbd_
                        if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
                                drbd_uuid_new_current(mdev);
                                clear_bit(NEW_CUR_UUID, &mdev->flags);
-                               drbd_md_sync(mdev);
                        }
                        spin_lock_irq(&mdev->req_lock);
                        _drbd_set_state(_NS(mdev, susp_fen, 0), CS_VERBOSE, NULL);
            os.disk > D_INCONSISTENT && ns.disk == D_INCONSISTENT)
                drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL, "set_n_write from invalidate");
  
-       /* first half of local IO error */
-       if (os.disk > D_FAILED && ns.disk == D_FAILED) {
-               enum drbd_io_error_p eh = EP_PASS_ON;
+       /* first half of local IO error, failure to attach,
+        * or administrative detach */
+       if (os.disk != D_FAILED && ns.disk == D_FAILED) {
+               enum drbd_io_error_p eh;
+               int was_io_error;
+               /* corresponding get_ldev was in __drbd_set_state, to serialize
+                * our cleanup here with the transition to D_DISKLESS,
+                * so it is safe to dreference ldev here. */
+               eh = mdev->ldev->dc.on_io_error;
+               was_io_error = test_and_clear_bit(WAS_IO_ERROR, &mdev->flags);
+               /* current state still has to be D_FAILED,
+                * there is only one way out: to D_DISKLESS,
+                * and that may only happen after our put_ldev below. */
+               if (mdev->state.disk != D_FAILED)
+                       dev_err(DEV,
+                               "ASSERT FAILED: disk is %s during detach\n",
+                               drbd_disk_str(mdev->state.disk));
  
                if (drbd_send_state(mdev))
-                       dev_warn(DEV, "Notified peer that my disk is broken.\n");
+                       dev_warn(DEV, "Notified peer that I am detaching my disk\n");
                else
-                       dev_err(DEV, "Sending state for drbd_io_error() failed\n");
+                       dev_err(DEV, "Sending state for detaching disk failed\n");
  
                drbd_rs_cancel_all(mdev);
  
-               if (get_ldev_if_state(mdev, D_FAILED)) {
-                       eh = mdev->ldev->dc.on_io_error;
-                       put_ldev(mdev);
-               }
-               if (eh == EP_CALL_HELPER)
+               /* In case we want to get something to stable storage still,
+                * this may be the last chance.
+                * Following put_ldev may transition to D_DISKLESS. */
+               drbd_md_sync(mdev);
+               put_ldev(mdev);
+               if (was_io_error && eh == EP_CALL_HELPER)
                        drbd_khelper(mdev, "local-io-error");
        }
  
+         /* second half of local IO error, failure to attach,
+          * or administrative detach,
+          * after local_cnt references have reached zero again */
+         if (os.disk != D_DISKLESS && ns.disk == D_DISKLESS) {
+                 /* We must still be diskless,
+                  * re-attach has to be serialized with this! */
+                 if (mdev->state.disk != D_DISKLESS)
+                         dev_err(DEV,
+                                 "ASSERT FAILED: disk is %s while going diskless\n",
+                                 drbd_disk_str(mdev->state.disk));
  
-       /* second half of local IO error handling,
-        * after local_cnt references have reached zero: */
-       if (os.disk == D_FAILED && ns.disk == D_DISKLESS) {
-               mdev->rs_total = 0;
-               mdev->rs_failed = 0;
-               atomic_set(&mdev->rs_pending_cnt, 0);
-       }
-       if (os.disk > D_DISKLESS && ns.disk == D_DISKLESS) {
-               /* We must still be diskless,
-                * re-attach has to be serialized with this! */
-               if (mdev->state.disk != D_DISKLESS)
-                       dev_err(DEV,
-                               "ASSERT FAILED: disk is %s while going diskless\n",
-                               drbd_disk_str(mdev->state.disk));
+                 mdev->rs_total = 0;
+                 mdev->rs_failed = 0;
+                 atomic_set(&mdev->rs_pending_cnt, 0);
  
-               /* we cannot assert local_cnt == 0 here, as get_ldev_if_state
-                * will inc/dec it frequently. Since we became D_DISKLESS, no
-                * one has touched the protected members anymore, though, so we
-                * are safe to free them here. */
                if (drbd_send_state(mdev))
-                       dev_warn(DEV, "Notified peer that I detached my disk.\n");
+                       dev_warn(DEV, "Notified peer that I'm now diskless.\n");
                else
-                       dev_err(DEV, "Sending state for detach failed\n");
-               lc_destroy(mdev->resync);
-               mdev->resync = NULL;
-               lc_destroy(mdev->act_log);
-               mdev->act_log = NULL;
-               __no_warn(local,
-                       drbd_free_bc(mdev->ldev);
-                       mdev->ldev = NULL;);
-               if (mdev->md_io_tmpp) {
-                       __free_page(mdev->md_io_tmpp);
-                       mdev->md_io_tmpp = NULL;
-               }
+                       dev_err(DEV, "Sending state for being diskless failed\n");
+               /* corresponding get_ldev in __drbd_set_state
+                * this may finaly trigger drbd_ldev_destroy. */
+               put_ldev(mdev);
        }
  
        /* Disks got bigger while they were detached */
@@@ -2772,11 -2789,6 +2789,6 @@@ void drbd_init_set_defaults(struct drbd
  
        drbd_set_defaults(mdev);
  
-       /* for now, we do NOT yet support it,
-        * even though we start some framework
-        * to eventually support barriers */
-       set_bit(NO_BARRIER_SUPP, &mdev->flags);
        atomic_set(&mdev->ap_bio_cnt, 0);
        atomic_set(&mdev->ap_pending_cnt, 0);
        atomic_set(&mdev->rs_pending_cnt, 0);
        drbd_thread_init(mdev, &mdev->asender, drbd_asender);
  
        mdev->agreed_pro_version = PRO_VERSION_MAX;
-       mdev->write_ordering = WO_bio_barrier;
+       mdev->write_ordering = WO_bdev_flush;
        mdev->resync_wenr = LC_FREE;
  }
  
@@@ -2899,7 -2911,6 +2911,6 @@@ void drbd_mdev_cleanup(struct drbd_con
        D_ASSERT(list_empty(&mdev->resync_work.list));
        D_ASSERT(list_empty(&mdev->unplug_work.list));
        D_ASSERT(list_empty(&mdev->go_diskless.list));
  }
  
  
@@@ -2982,7 -2993,7 +2993,7 @@@ static int drbd_create_mempools(void
  
        drbd_ee_mempool = mempool_create(number,
                mempool_alloc_slab, mempool_free_slab, drbd_ee_cache);
 -      if (drbd_request_mempool == NULL)
 +      if (drbd_ee_mempool == NULL)
                goto Enomem;
  
        /* drbd's page pool */
@@@ -3660,6 -3671,8 +3671,8 @@@ void drbd_uuid_new_current(struct drbd_
  
        get_random_bytes(&val, sizeof(u64));
        _drbd_uuid_set(mdev, UI_CURRENT, val);
+       /* get it to stable storage _now_ */
+       drbd_md_sync(mdev);
  }
  
  void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local)
@@@ -3756,19 -3769,31 +3769,31 @@@ static int w_bitmap_io(struct drbd_con
        return 1;
  }
  
+ void drbd_ldev_destroy(struct drbd_conf *mdev)
+ {
+       lc_destroy(mdev->resync);
+       mdev->resync = NULL;
+       lc_destroy(mdev->act_log);
+       mdev->act_log = NULL;
+       __no_warn(local,
+               drbd_free_bc(mdev->ldev);
+               mdev->ldev = NULL;);
+       if (mdev->md_io_tmpp) {
+               __free_page(mdev->md_io_tmpp);
+               mdev->md_io_tmpp = NULL;
+       }
+       clear_bit(GO_DISKLESS, &mdev->flags);
+ }
  static int w_go_diskless(struct drbd_conf *mdev, struct drbd_work *w, int unused)
  {
        D_ASSERT(mdev->state.disk == D_FAILED);
        /* we cannot assert local_cnt == 0 here, as get_ldev_if_state will
         * inc/dec it frequently. Once we are D_DISKLESS, no one will touch
-        * the protected members anymore, though, so in the after_state_ch work
-        * it will be safe to free them. */
+        * the protected members anymore, though, so once put_ldev reaches zero
+        * again, it will be safe to free them. */
        drbd_force_state(mdev, NS(disk, D_DISKLESS));
-       /* We need to wait for return of references checked out while we still
-        * have been D_FAILED, though (drbd_md_sync, bitmap io). */
-       wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
-       clear_bit(GO_DISKLESS, &mdev->flags);
        return 1;
  }
  
@@@ -3777,9 -3802,6 +3802,6 @@@ void drbd_go_diskless(struct drbd_conf 
        D_ASSERT(mdev->state.disk == D_FAILED);
        if (!test_and_set_bit(GO_DISKLESS, &mdev->flags))
                drbd_queue_work(&mdev->data.work, &mdev->go_diskless);
-               /* don't drbd_queue_work_front,
-                * we need to serialize with the after_state_ch work
-                * of the -> D_FAILED transition. */
  }
  
  /**