To avoid erasing a device with a mounted filesystem, try to get exclusive
access to the blkdev object corresponding to the device.

Signed-off-by: Selvan Mani <sm...@micron.com>
Signed-off-by: Rajesh Kumar Sambandam <rsamban...@micron.com>
Signed-off-by: Asai Thambi S P <asamymuth...@micron.com>
---
 drivers/block/mtip32xx/mtip32xx.c |  113 ++++++++++++++++++++++++++++++-------
 drivers/block/mtip32xx/mtip32xx.h |    2 +
 2 files changed, 94 insertions(+), 21 deletions(-)

diff --git a/drivers/block/mtip32xx/mtip32xx.c 
b/drivers/block/mtip32xx/mtip32xx.c
index 9b180db..37690ab 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -982,6 +982,28 @@ static void mtip_issue_non_ncq_command(struct mtip_port 
*port, int tag)
         port->cmd_issue[MTIP_TAG_INDEX(tag)]);
 }
 
+static inline int mtip_bdev_claim(struct driver_data *dd)
+{
+    if (dd->bdev_claimed == false) {
+        igrab(dd->bdev->bd_inode);
+        if (blkdev_get(dd->bdev, FMODE_EXCL, dd->bdev) < 0) {
+            dev_warn(&dd->pdev->dev, "Drive erase aborted due to non-zero 
refcount (%d)\n",
+                dd->bdev->bd_holders);
+            return -ERESTARTSYS;
+        }
+        dd->bdev_claimed = true;
+    }
+    return 0;
+}
+
+static inline void mtip_bdev_unclaim(struct driver_data *dd)
+{
+    if (dd->bdev_claimed) {
+        blkdev_put(dd->bdev, FMODE_EXCL);
+        dd->bdev_claimed = false;
+    }
+}
+
 static bool mtip_pause_ncq(struct mtip_port *port,
                 struct host_to_dev_fis *fis)
 {
@@ -991,10 +1013,21 @@ static bool mtip_pause_ncq(struct mtip_port *port,
     reply = port->rxfis + RX_FIS_D2H_REG;
     task_file_data = readl(port->mmio+PORT_TFDATA);
 
-    if ((task_file_data & 1))
+    if ((task_file_data & 1)) {
+        if ((fis->command == ATA_CMD_SEC_SET_PASS) ||
+            (fis->command == ATA_CMD_SEC_ERASE_PREP) ||
+            (fis->command == ATA_CMD_SEC_ERASE_UNIT) ||
+            ((fis->command == 0xFC) &&
+                (fis->features == 0x27 || fis->features == 0x72 ||
+                 fis->features == 0x62 || fis->features == 0x26 ||
+                 fis->features == 0x12)))
+            mtip_bdev_unclaim(port->dd);
         return false;
+    }
 
-    if (fis->command == ATA_CMD_SEC_ERASE_PREP) {
+    if (fis->command == ATA_CMD_SEC_SET_PASS) {
+        mtip_bdev_unclaim(port->dd);
+    } else if (fis->command == ATA_CMD_SEC_ERASE_PREP) {
         port->ic_pause_timer = jiffies;
         return true;
     } else if ((fis->command == ATA_CMD_DOWNLOAD_MICRO) &&
@@ -1005,8 +1038,10 @@ static bool mtip_pause_ncq(struct mtip_port *port,
     } else if ((fis->command == ATA_CMD_SEC_ERASE_UNIT) ||
         ((fis->command == 0xFC) &&
             (fis->features == 0x27 || fis->features == 0x72 ||
-             fis->features == 0x62 || fis->features == 0x26))) {
+             fis->features == 0x62 || fis->features == 0x26 ||
+             fis->features == 0x12))) {
         clear_bit(MTIP_DDF_SEC_LOCK_BIT, &port->dd->dd_flag);
+        mtip_bdev_unclaim(port->dd);
         /* Com reset after secure erase or lowlevel format */
         mtip_restart_port(port);
         clear_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags);
@@ -1110,8 +1145,23 @@ static int mtip_exec_internal_command(struct mtip_port 
*port,
 
     set_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags);
 
+    /* Check for secure erase while fs mounted */
+    if ((fis->command == ATA_CMD_SEC_SET_PASS) ||
+        (fis->command == ATA_CMD_SEC_ERASE_PREP) ||
+        (fis->command == ATA_CMD_SEC_ERASE_UNIT) ||
+        ((fis->command == 0xFC) &&
+            (fis->features == 0x27 || fis->features == 0x72 ||
+             fis->features == 0x62 || fis->features == 0x26 ||
+             fis->features == 0x12))) {
+        rv = mtip_bdev_claim(dd);
+        if (rv)
+            goto exec_ic_exit;
+    }
+
     if (fis->command == ATA_CMD_SEC_ERASE_PREP)
         set_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags);
+    else if (fis->command == ATA_CMD_SEC_ERASE_UNIT)
+        dd->port->ic_pause_timer = 0;
 
     clear_bit(MTIP_PF_DM_ACTIVE_BIT, &port->flags);
 
@@ -1122,6 +1172,8 @@ static int mtip_exec_internal_command(struct mtip_port 
*port,
                     MTIP_QUIESCE_IO_TIMEOUT_MS) < 0) {
                 dev_warn(&dd->pdev->dev,
                     "Failed to quiesce IO\n");
+
+                mtip_bdev_unclaim(dd);
                 mtip_put_int_command(dd, int_cmd);
                 clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags);
                 wake_up_interruptible(&port->svc_wait);
@@ -1197,6 +1249,8 @@ static int mtip_exec_internal_command(struct mtip_port 
*port,
             mtip_device_reset(dd); /* recover from timeout issue */
             rv = -EAGAIN;
             goto exec_ic_exit;
+        } else {
+            rv = 0;
         }
     } else {
         u32 hba_stat, port_stat;
@@ -1247,6 +1301,10 @@ static int mtip_exec_internal_command(struct mtip_port 
*port,
         }
     }
 exec_ic_exit:
+    if (rv < 0) {
+        clear_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags);
+        mtip_bdev_unclaim(dd);
+    }
     /* Clear the allocated and active bits for the internal command. */
     mtip_put_int_command(dd, int_cmd);
     clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags);
@@ -1783,6 +1841,7 @@ static int exec_drive_task(struct mtip_port *port, u8 
*command)
     struct host_to_dev_fis    fis;
     struct host_to_dev_fis *reply = (port->rxfis + RX_FIS_D2H_REG);
     unsigned int to;
+    int rv;
 
     /* Build the FIS. */
     memset(&fis, 0, sizeof(struct host_to_dev_fis));
@@ -1809,14 +1868,17 @@ static int exec_drive_task(struct mtip_port *port, u8 
*command)
         command[6]);
 
     /* Execute the command. */
-    if (mtip_exec_internal_command(port,
+    rv = mtip_exec_internal_command(port,
                  &fis,
                  5,
                  0,
                  0,
                  0,
                  GFP_KERNEL,
-                 to) < 0) {
+                 to);
+    if (rv < 0) {
+        if (rv == -ERESTARTSYS)
+            return rv;
         return -1;
     }
 
@@ -1905,16 +1967,17 @@ static int exec_drive_command(struct mtip_port *port, 
u8 *command,
         command[3]);
 
     /* Execute the command. */
-    if (mtip_exec_internal_command(port,
+    rv = mtip_exec_internal_command(port,
                 &fis,
                  5,
                  (xfer_sz ? dma_addr : 0),
                  (xfer_sz ? ATA_SECT_SIZE * xfer_sz : 0),
                  0,
                  GFP_KERNEL,
-                 to)
-                 < 0) {
-        rv = -EFAULT;
+                 to);
+    if (rv < 0) {
+        if (rv != -ERESTARTSYS)
+            rv = -EFAULT;
         goto exit_drive_command;
     }
 
@@ -2152,15 +2215,17 @@ static int exec_drive_taskfile(struct driver_data *dd,
         transfer_size = ATA_SECT_SIZE * fis.sect_count;
 
     /* Execute the command.*/
-    if (mtip_exec_internal_command(dd->port,
+    err = mtip_exec_internal_command(dd->port,
                  &fis,
                  5,
                  dma_buffer,
                  transfer_size,
                  0,
                  GFP_KERNEL,
-                 timeout) < 0) {
-        err = -EIO;
+                 timeout);
+    if (err < 0) {
+        if (err != -ERESTARTSYS)
+            err = -EIO;
         goto abort;
     }
 
@@ -2258,6 +2323,8 @@ abort:
 static int mtip_hw_ioctl(struct driver_data *dd, unsigned int cmd,
              unsigned long arg)
 {
+    int ret = 0;
+
     switch (cmd) {
     case HDIO_GET_IDENTITY:
     {
@@ -2277,10 +2344,11 @@ static int mtip_hw_ioctl(struct driver_data *dd, 
unsigned int cmd,
             return -EFAULT;
 
         /* Execute the drive command. */
-        if (exec_drive_command(dd->port,
+        ret = exec_drive_command(dd->port,
                      drive_command,
-                     (void __user *) (arg+4)))
-            return -EIO;
+                     (void __user *) (arg+4));
+        if (ret < 0)
+            return ret;
 
         /* Copy the status back to the users buffer. */
         if (copy_to_user((void __user *) arg,
@@ -2301,8 +2369,9 @@ static int mtip_hw_ioctl(struct driver_data *dd, unsigned 
int cmd,
             return -EFAULT;
 
         /* Execute the drive command. */
-        if (exec_drive_task(dd->port, drive_command))
-            return -EIO;
+        ret = exec_drive_task(dd->port, drive_command);
+        if (ret < 0)
+            return ret;
 
         /* Copy the status back to the users buffer. */
         if (copy_to_user((void __user *) arg,
@@ -2314,7 +2383,7 @@ static int mtip_hw_ioctl(struct driver_data *dd, unsigned 
int cmd,
     }
     case HDIO_DRIVE_TASKFILE: {
         ide_task_request_t req_task;
-        int ret, outtotal;
+        int outtotal;
 
         if (copy_from_user(&req_task, (void __user *) arg,
                     sizeof(req_task)))
@@ -2329,13 +2398,13 @@ static int mtip_hw_ioctl(struct driver_data *dd, 
unsigned int cmd,
                             sizeof(req_task)))
             return -EFAULT;
 
-        return ret;
+        break;
     }
 
     default:
         return -EINVAL;
     }
-    return 0;
+    return ret;
 }
 
 /*
@@ -3620,7 +3689,7 @@ static inline bool is_se_active(struct driver_data *dd)
             if (time_after(jiffies, to)) {
                 clear_bit(MTIP_PF_SE_ACTIVE_BIT,
                             &dd->port->flags);
-                clear_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag);
+                mtip_bdev_unclaim(dd);
                 dd->port->ic_pause_timer = 0;
                 wake_up_interruptible(&dd->port->svc_wait);
                 return false;
@@ -3934,6 +4003,7 @@ skip_create_disk:
     add_disk(dd->disk);
 
     dd->bdev = bdget_disk(dd->disk, 0);
+    dd->bdev_claimed = false;
     /*
      * Now that the disk is active, initialize any sysfs attributes
      * managed by the protocol layer.
@@ -4008,6 +4078,7 @@ static int mtip_block_remove(struct driver_data *dd)
 {
     struct kobject *kobj;
 
+    mtip_bdev_unclaim(dd);
     mtip_hw_debugfs_exit(dd);
 
     if (dd->mtip_svc_handler) {
diff --git a/drivers/block/mtip32xx/mtip32xx.h 
b/drivers/block/mtip32xx/mtip32xx.h
index 3274784..29357fd 100644
--- a/drivers/block/mtip32xx/mtip32xx.h
+++ b/drivers/block/mtip32xx/mtip32xx.h
@@ -491,6 +491,8 @@ struct driver_data {
 
     int isr_binding;
 
+    bool bdev_claimed; /* set when bdev is claimed exclusively */
+
     struct block_device *bdev;
 
     struct list_head online_list; /* linkage for online list */
-- 
1.7.1


Reply via email to