Merge tag 'trace-v5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
[linux-2.6-microblaze.git] / drivers / target / target_core_user.c
index a5991df..bf73cd5 100644 (file)
@@ -1566,6 +1566,88 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name)
        return &udev->se_dev;
 }
 
+static void tcmu_dev_call_rcu(struct rcu_head *p)
+{
+       struct se_device *dev = container_of(p, struct se_device, rcu_head);
+       struct tcmu_dev *udev = TCMU_DEV(dev);
+
+       kfree(udev->uio_info.name);
+       kfree(udev->name);
+       kfree(udev);
+}
+
+static int tcmu_check_and_free_pending_cmd(struct tcmu_cmd *cmd)
+{
+       if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {
+               kmem_cache_free(tcmu_cmd_cache, cmd);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static void tcmu_blocks_release(struct radix_tree_root *blocks,
+                               int start, int end)
+{
+       int i;
+       struct page *page;
+
+       for (i = start; i < end; i++) {
+               page = radix_tree_delete(blocks, i);
+               if (page) {
+                       __free_page(page);
+                       atomic_dec(&global_db_count);
+               }
+       }
+}
+
+static void tcmu_remove_all_queued_tmr(struct tcmu_dev *udev)
+{
+       struct tcmu_tmr *tmr, *tmp;
+
+       list_for_each_entry_safe(tmr, tmp, &udev->tmr_queue, queue_entry) {
+               list_del_init(&tmr->queue_entry);
+               kfree(tmr);
+       }
+}
+
+static void tcmu_dev_kref_release(struct kref *kref)
+{
+       struct tcmu_dev *udev = container_of(kref, struct tcmu_dev, kref);
+       struct se_device *dev = &udev->se_dev;
+       struct tcmu_cmd *cmd;
+       bool all_expired = true;
+       int i;
+
+       vfree(udev->mb_addr);
+       udev->mb_addr = NULL;
+
+       spin_lock_bh(&timed_out_udevs_lock);
+       if (!list_empty(&udev->timedout_entry))
+               list_del(&udev->timedout_entry);
+       spin_unlock_bh(&timed_out_udevs_lock);
+
+       /* Upper layer should drain all requests before calling this */
+       mutex_lock(&udev->cmdr_lock);
+       idr_for_each_entry(&udev->commands, cmd, i) {
+               if (tcmu_check_and_free_pending_cmd(cmd) != 0)
+                       all_expired = false;
+       }
+       /* There can be left over TMR cmds. Remove them. */
+       tcmu_remove_all_queued_tmr(udev);
+       if (!list_empty(&udev->qfull_queue))
+               all_expired = false;
+       idr_destroy(&udev->commands);
+       WARN_ON(!all_expired);
+
+       tcmu_blocks_release(&udev->data_blocks, 0, udev->dbi_max + 1);
+       bitmap_free(udev->data_bitmap);
+       mutex_unlock(&udev->cmdr_lock);
+
+       pr_debug("dev_kref_release\n");
+
+       call_rcu(&dev->rcu_head, tcmu_dev_call_rcu);
+}
+
 static void run_qfull_queue(struct tcmu_dev *udev, bool fail)
 {
        struct tcmu_cmd *tcmu_cmd, *tmp_cmd;
@@ -1678,6 +1760,25 @@ static struct page *tcmu_try_get_block_page(struct tcmu_dev *udev, uint32_t dbi)
        return page;
 }
 
+static void tcmu_vma_open(struct vm_area_struct *vma)
+{
+       struct tcmu_dev *udev = vma->vm_private_data;
+
+       pr_debug("vma_open\n");
+
+       kref_get(&udev->kref);
+}
+
+static void tcmu_vma_close(struct vm_area_struct *vma)
+{
+       struct tcmu_dev *udev = vma->vm_private_data;
+
+       pr_debug("vma_close\n");
+
+       /* release ref from tcmu_vma_open */
+       kref_put(&udev->kref, tcmu_dev_kref_release);
+}
+
 static vm_fault_t tcmu_vma_fault(struct vm_fault *vmf)
 {
        struct tcmu_dev *udev = vmf->vma->vm_private_data;
@@ -1716,6 +1817,8 @@ static vm_fault_t tcmu_vma_fault(struct vm_fault *vmf)
 }
 
 static const struct vm_operations_struct tcmu_vm_ops = {
+       .open = tcmu_vma_open,
+       .close = tcmu_vma_close,
        .fault = tcmu_vma_fault,
 };
 
@@ -1732,6 +1835,8 @@ static int tcmu_mmap(struct uio_info *info, struct vm_area_struct *vma)
        if (vma_pages(vma) != (udev->ring_size >> PAGE_SHIFT))
                return -EINVAL;
 
+       tcmu_vma_open(vma);
+
        return 0;
 }
 
@@ -1744,93 +1849,12 @@ static int tcmu_open(struct uio_info *info, struct inode *inode)
                return -EBUSY;
 
        udev->inode = inode;
-       kref_get(&udev->kref);
 
        pr_debug("open\n");
 
        return 0;
 }
 
-static void tcmu_dev_call_rcu(struct rcu_head *p)
-{
-       struct se_device *dev = container_of(p, struct se_device, rcu_head);
-       struct tcmu_dev *udev = TCMU_DEV(dev);
-
-       kfree(udev->uio_info.name);
-       kfree(udev->name);
-       kfree(udev);
-}
-
-static int tcmu_check_and_free_pending_cmd(struct tcmu_cmd *cmd)
-{
-       if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {
-               kmem_cache_free(tcmu_cmd_cache, cmd);
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static void tcmu_blocks_release(struct radix_tree_root *blocks,
-                               int start, int end)
-{
-       int i;
-       struct page *page;
-
-       for (i = start; i < end; i++) {
-               page = radix_tree_delete(blocks, i);
-               if (page) {
-                       __free_page(page);
-                       atomic_dec(&global_db_count);
-               }
-       }
-}
-
-static void tcmu_remove_all_queued_tmr(struct tcmu_dev *udev)
-{
-       struct tcmu_tmr *tmr, *tmp;
-
-       list_for_each_entry_safe(tmr, tmp, &udev->tmr_queue, queue_entry) {
-               list_del_init(&tmr->queue_entry);
-               kfree(tmr);
-       }
-}
-
-static void tcmu_dev_kref_release(struct kref *kref)
-{
-       struct tcmu_dev *udev = container_of(kref, struct tcmu_dev, kref);
-       struct se_device *dev = &udev->se_dev;
-       struct tcmu_cmd *cmd;
-       bool all_expired = true;
-       int i;
-
-       vfree(udev->mb_addr);
-       udev->mb_addr = NULL;
-
-       spin_lock_bh(&timed_out_udevs_lock);
-       if (!list_empty(&udev->timedout_entry))
-               list_del(&udev->timedout_entry);
-       spin_unlock_bh(&timed_out_udevs_lock);
-
-       /* Upper layer should drain all requests before calling this */
-       mutex_lock(&udev->cmdr_lock);
-       idr_for_each_entry(&udev->commands, cmd, i) {
-               if (tcmu_check_and_free_pending_cmd(cmd) != 0)
-                       all_expired = false;
-       }
-       /* There can be left over TMR cmds. Remove them. */
-       tcmu_remove_all_queued_tmr(udev);
-       if (!list_empty(&udev->qfull_queue))
-               all_expired = false;
-       idr_destroy(&udev->commands);
-       WARN_ON(!all_expired);
-
-       tcmu_blocks_release(&udev->data_blocks, 0, udev->dbi_max + 1);
-       bitmap_free(udev->data_bitmap);
-       mutex_unlock(&udev->cmdr_lock);
-
-       call_rcu(&dev->rcu_head, tcmu_dev_call_rcu);
-}
-
 static int tcmu_release(struct uio_info *info, struct inode *inode)
 {
        struct tcmu_dev *udev = container_of(info, struct tcmu_dev, uio_info);
@@ -1838,8 +1862,7 @@ static int tcmu_release(struct uio_info *info, struct inode *inode)
        clear_bit(TCMU_DEV_BIT_OPEN, &udev->flags);
 
        pr_debug("close\n");
-       /* release ref from open */
-       kref_put(&udev->kref, tcmu_dev_kref_release);
+
        return 0;
 }