ublk: rename mm_lock as lock
[linux-block.git] / drivers / block / ublk_drv.c
index 630ddfe6657bc9076b3853f8e100b3ca2fd8e70d..01cd2be1df0e5341ba11550a2e145cffa08b68b0 100644 (file)
@@ -115,6 +115,9 @@ struct ublk_uring_cmd_pdu {
  */
 #define UBLK_IO_FLAG_NEED_GET_DATA 0x08
 
+/* atomic RW with ubq->cancel_lock */
+#define UBLK_IO_FLAG_CANCELED  0x80000000
+
 struct ublk_io {
        /* userspace buffer address from io cmd */
        __u64   addr;
@@ -139,6 +142,7 @@ struct ublk_queue {
        bool force_abort;
        bool timeout;
        unsigned short nr_io_ready;     /* how many ios setup */
+       spinlock_t              cancel_lock;
        struct ublk_device *dev;
        struct ublk_io ios[];
 };
@@ -166,7 +170,7 @@ struct ublk_device {
 
        struct mutex            mutex;
 
-       spinlock_t              mm_lock;
+       spinlock_t              lock;
        struct mm_struct        *mm;
 
        struct ublk_params      params;
@@ -470,6 +474,7 @@ static DEFINE_MUTEX(ublk_ctl_mutex);
  * It can be extended to one per-user limit in future or even controlled
  * by cgroup.
  */
+#define UBLK_MAX_UBLKS UBLK_MINORS
 static unsigned int ublks_max = 64;
 static unsigned int ublks_added;       /* protected by ublk_ctl_mutex */
 
@@ -1357,12 +1362,12 @@ static int ublk_ch_mmap(struct file *filp, struct vm_area_struct *vma)
        unsigned long pfn, end, phys_off = vma->vm_pgoff << PAGE_SHIFT;
        int q_id, ret = 0;
 
-       spin_lock(&ub->mm_lock);
+       spin_lock(&ub->lock);
        if (!ub->mm)
                ub->mm = current->mm;
        if (current->mm != ub->mm)
                ret = -EINVAL;
-       spin_unlock(&ub->mm_lock);
+       spin_unlock(&ub->lock);
 
        if (ret)
                return ret;
@@ -1419,9 +1424,6 @@ static void ublk_abort_queue(struct ublk_device *ub, struct ublk_queue *ubq)
 {
        int i;
 
-       if (!ublk_get_device(ub))
-               return;
-
        for (i = 0; i < ubq->q_depth; i++) {
                struct ublk_io *io = &ubq->ios[i];
 
@@ -1437,7 +1439,6 @@ static void ublk_abort_queue(struct ublk_device *ub, struct ublk_queue *ubq)
                                __ublk_fail_req(ubq, io, rq);
                }
        }
-       ublk_put_device(ub);
 }
 
 static void ublk_daemon_monitor_work(struct work_struct *work)
@@ -1477,28 +1478,28 @@ static inline bool ublk_queue_ready(struct ublk_queue *ubq)
        return ubq->nr_io_ready == ubq->q_depth;
 }
 
-static void ublk_cmd_cancel_cb(struct io_uring_cmd *cmd, unsigned issue_flags)
-{
-       io_uring_cmd_done(cmd, UBLK_IO_RES_ABORT, 0, issue_flags);
-}
-
 static void ublk_cancel_queue(struct ublk_queue *ubq)
 {
        int i;
 
-       if (!ublk_queue_ready(ubq))
-               return;
-
        for (i = 0; i < ubq->q_depth; i++) {
                struct ublk_io *io = &ubq->ios[i];
 
-               if (io->flags & UBLK_IO_FLAG_ACTIVE)
-                       io_uring_cmd_complete_in_task(io->cmd,
-                                                     ublk_cmd_cancel_cb);
-       }
+               if (io->flags & UBLK_IO_FLAG_ACTIVE) {
+                       bool done;
 
-       /* all io commands are canceled */
-       ubq->nr_io_ready = 0;
+                       spin_lock(&ubq->cancel_lock);
+                       done = !!(io->flags & UBLK_IO_FLAG_CANCELED);
+                       if (!done)
+                               io->flags |= UBLK_IO_FLAG_CANCELED;
+                       spin_unlock(&ubq->cancel_lock);
+
+                       if (!done)
+                               io_uring_cmd_done(io->cmd,
+                                               UBLK_IO_RES_ABORT, 0,
+                                               IO_URING_F_UNLOCKED);
+               }
+       }
 }
 
 /* Cancel all pending commands, must be called after del_gendisk() returns */
@@ -1545,7 +1546,6 @@ static void __ublk_quiesce_dev(struct ublk_device *ub)
        blk_mq_quiesce_queue(ub->ub_disk->queue);
        ublk_wait_tagset_rqs_idle(ub);
        ub->dev_info.state = UBLK_S_DEV_QUIESCED;
-       ublk_cancel_dev(ub);
        /* we are going to release task_struct of ubq_daemon and resets
         * ->ubq_daemon to NULL. So in monitor_work, check on ubq_daemon causes UAF.
         * Besides, monitor_work is not necessary in QUIESCED state since we have
@@ -1568,6 +1568,7 @@ static void ublk_quiesce_work_fn(struct work_struct *work)
        __ublk_quiesce_dev(ub);
  unlock:
        mutex_unlock(&ub->mutex);
+       ublk_cancel_dev(ub);
 }
 
 static void ublk_unquiesce_dev(struct ublk_device *ub)
@@ -1607,8 +1608,8 @@ static void ublk_stop_dev(struct ublk_device *ub)
        put_disk(ub->ub_disk);
        ub->ub_disk = NULL;
  unlock:
-       ublk_cancel_dev(ub);
        mutex_unlock(&ub->mutex);
+       ublk_cancel_dev(ub);
        cancel_delayed_work_sync(&ub->monitor_work);
 }
 
@@ -1814,7 +1815,8 @@ fail_put:
        return NULL;
 }
 
-static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
+static inline int ublk_ch_uring_cmd_local(struct io_uring_cmd *cmd,
+               unsigned int issue_flags)
 {
        /*
         * Not necessary for async retry, but let's keep it simple and always
@@ -1828,9 +1830,28 @@ static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
                .addr = READ_ONCE(ub_src->addr)
        };
 
+       WARN_ON_ONCE(issue_flags & IO_URING_F_UNLOCKED);
+
        return __ublk_ch_uring_cmd(cmd, issue_flags, &ub_cmd);
 }
 
+static void ublk_ch_uring_cmd_cb(struct io_uring_cmd *cmd,
+               unsigned int issue_flags)
+{
+       ublk_ch_uring_cmd_local(cmd, issue_flags);
+}
+
+static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
+{
+       /* well-implemented server won't run into unlocked */
+       if (unlikely(issue_flags & IO_URING_F_UNLOCKED)) {
+               io_uring_cmd_complete_in_task(cmd, ublk_ch_uring_cmd_cb);
+               return -EIOCBQUEUED;
+       }
+
+       return ublk_ch_uring_cmd_local(cmd, issue_flags);
+}
+
 static inline bool ublk_check_ubuf_dir(const struct request *req,
                int ubuf_dir)
 {
@@ -1962,6 +1983,7 @@ static int ublk_init_queue(struct ublk_device *ub, int q_id)
        void *ptr;
        int size;
 
+       spin_lock_init(&ubq->cancel_lock);
        ubq->flags = ub->dev_info.flags;
        ubq->q_id = q_id;
        ubq->q_depth = ub->dev_info.queue_depth;
@@ -2026,7 +2048,8 @@ static int ublk_alloc_dev_number(struct ublk_device *ub, int idx)
                if (err == -ENOSPC)
                        err = -EEXIST;
        } else {
-               err = idr_alloc(&ublk_index_idr, ub, 0, 0, GFP_NOWAIT);
+               err = idr_alloc(&ublk_index_idr, ub, 0, UBLK_MAX_UBLKS,
+                               GFP_NOWAIT);
        }
        spin_unlock(&ublk_idr_lock);
 
@@ -2305,6 +2328,12 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd)
                return -EINVAL;
        }
 
+       if (header->dev_id != U32_MAX && header->dev_id >= UBLK_MAX_UBLKS) {
+               pr_warn("%s: dev id is too large. Max supported is %d\n",
+                       __func__, UBLK_MAX_UBLKS - 1);
+               return -EINVAL;
+       }
+
        ublk_dump_dev_info(&info);
 
        ret = mutex_lock_killable(&ublk_ctl_mutex);
@@ -2320,7 +2349,7 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd)
        if (!ub)
                goto out_unlock;
        mutex_init(&ub->mutex);
-       spin_lock_init(&ub->mm_lock);
+       spin_lock_init(&ub->lock);
        INIT_WORK(&ub->quiesce_work, ublk_quiesce_work_fn);
        INIT_WORK(&ub->stop_work, ublk_stop_work_fn);
        INIT_DELAYED_WORK(&ub->monitor_work, ublk_daemon_monitor_work);
@@ -2569,8 +2598,9 @@ static void ublk_queue_reinit(struct ublk_device *ub, struct ublk_queue *ubq)
        int i;
 
        WARN_ON_ONCE(!(ubq->ubq_daemon && ubq_daemon_is_dying(ubq)));
+
        /* All old ioucmds have to be completed */
-       WARN_ON_ONCE(ubq->nr_io_ready);
+       ubq->nr_io_ready = 0;
        /* old daemon is PF_EXITING, put it now */
        put_task_struct(ubq->ubq_daemon);
        /* We have to reset it to NULL, otherwise ub won't accept new FETCH_REQ */
@@ -2932,7 +2962,22 @@ static void __exit ublk_exit(void)
 module_init(ublk_init);
 module_exit(ublk_exit);
 
-module_param(ublks_max, int, 0444);
+static int ublk_set_max_ublks(const char *buf, const struct kernel_param *kp)
+{
+       return param_set_uint_minmax(buf, kp, 0, UBLK_MAX_UBLKS);
+}
+
+static int ublk_get_max_ublks(char *buf, const struct kernel_param *kp)
+{
+       return sysfs_emit(buf, "%u\n", ublks_max);
+}
+
+static const struct kernel_param_ops ublk_max_ublks_ops = {
+       .set = ublk_set_max_ublks,
+       .get = ublk_get_max_ublks,
+};
+
+module_param_cb(ublks_max, &ublk_max_ublks_ops, &ublks_max, 0644);
 MODULE_PARM_DESC(ublks_max, "max number of ublk devices allowed to add(default: 64)");
 
 MODULE_AUTHOR("Ming Lei <ming.lei@redhat.com>");