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