diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index dc9301d31f12..e74aef904fd4 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -47,6 +47,13 @@ enum { VHOST_MEMORY_F_LOG = 0x1, }; +void vhost_debug_mm(struct vhost_dev *dev, const char *prompt) +{ + printk("%s mm_count %d mm_users %d\n", + prompt, atomic_read(&dev->mm->mm_count), + atomic_read(&dev->mm->mm_users)); +} + #define vhost_used_event(vq) ((__virtio16 __user *)&vq->avail->ring[vq->num]) #define vhost_avail_event(vq) ((__virtio16 __user *)&vq->used->ring[vq->num]) @@ -496,7 +503,9 @@ static int vhost_worker(void *data) mm_segment_t oldfs = get_fs(); set_fs(USER_DS); + vhost_debug_mm(dev, "in worker"); use_mm(dev->mm); + vhost_debug_mm(dev, "after use mm"); for (;;) { /* mb paired w/ kthread_stop */ @@ -508,8 +517,10 @@ static int vhost_worker(void *data) } node = llist_del_all(&dev->work_list); - if (!node) + if (!node) { + vhost_debug_mm(dev, "schedule1"); schedule(); + } node = llist_reverse_order(node); /* make sure flag is seen after deletion */ @@ -518,11 +529,14 @@ static int vhost_worker(void *data) clear_bit(VHOST_WORK_QUEUED, &work->flags); __set_current_state(TASK_RUNNING); work->fn(work); - if (need_resched()) + if (need_resched()) { + vhost_debug_mm(dev, "schedule2"); schedule(); + } } } unuse_mm(dev->mm); + vhost_debug_mm(dev, "after unused"); set_fs(oldfs); return 0; } @@ -709,6 +723,8 @@ long vhost_dev_set_owner(struct vhost_dev *dev) /* No owner, become one */ dev->mm = get_task_mm(current); + debug_mm = dev->mm; + vhost_debug_mm(dev, "set owner"); worker = kthread_create(vhost_worker, dev, "vhost-%d", current->pid); if (IS_ERR(worker)) { err = PTR_ERR(worker); @@ -730,6 +746,7 @@ long vhost_dev_set_owner(struct vhost_dev *dev) err = mmu_notifier_register(&dev->mmu_notifier, dev->mm); if (err) goto err_mmu_notifier; + vhost_debug_mm(dev, "after register in set_owner"); #endif return 0; @@ -742,8 +759,10 @@ long vhost_dev_set_owner(struct vhost_dev *dev) kthread_stop(worker); dev->worker = NULL; err_worker: - if (dev->mm) + if (dev->mm) { mmput(dev->mm); + vhost_debug_mm(dev, "err_worker"); + } dev->mm = NULL; err_mm: return err; @@ -940,7 +959,9 @@ void vhost_dev_cleanup(struct vhost_dev *dev) fput(dev->vqs[i]->kick); if (dev->vqs[i]->call_ctx) eventfd_ctx_put(dev->vqs[i]->call_ctx); + vhost_debug_mm(dev, "Before final reset!\n"); vhost_vq_reset(dev, dev->vqs[i]); + vhost_debug_mm(dev, "final reset!\n"); } vhost_dev_free_iovecs(dev); if (dev->log_ctx) @@ -963,12 +984,14 @@ void vhost_dev_cleanup(struct vhost_dev *dev) mmu_notifier_unregister(&dev->mmu_notifier, dev->mm); #endif mmput(dev->mm); + vhost_debug_mm(dev, "cleanup last"); } #if VHOST_ARCH_CAN_ACCEL_UACCESS for (i = 0; i < dev->nvqs; i++) vhost_uninit_vq_maps(dev->vqs[i]); #endif dev->mm = NULL; + debug_mm = NULL; } EXPORT_SYMBOL_GPL(vhost_dev_cleanup); @@ -2067,8 +2090,10 @@ static long vhost_vring_set_num_addr(struct vhost_dev *d, */ if (d->mm) mmu_notifier_unregister(&d->mmu_notifier, d->mm); + vhost_debug_mm(d, "unregister in set_num_addr"); vhost_uninit_vq_maps(vq); + vhost_debug_mm(d, "after uninit vq in set_vring_num"); #endif switch (ioctl) { @@ -2087,6 +2112,7 @@ static long vhost_vring_set_num_addr(struct vhost_dev *d, if (d->mm) mmu_notifier_register(&d->mmu_notifier, d->mm); + vhost_debug_mm(d, "after register in set_vring_num"); #endif mutex_unlock(&vq->mutex); diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 8ec38b11b361..3126d0c23763 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -515,6 +515,7 @@ struct mm_struct { }; extern struct mm_struct init_mm; +extern struct mm_struct *debug_mm; /* Pointer magic because the dynamic array size confuses some compilers. */ static inline void mm_init_cpumask(struct mm_struct *mm) diff --git a/include/linux/sched/mm.h b/include/linux/sched/mm.h index a3fda9f024c3..65497b7010ea 100644 --- a/include/linux/sched/mm.h +++ b/include/linux/sched/mm.h @@ -9,6 +9,7 @@ #include #include + /* * Routines for handling mm_structs */ @@ -33,6 +34,11 @@ extern struct mm_struct *mm_alloc(void); */ static inline void mmgrab(struct mm_struct *mm) { +#if 0 + if (debug_mm == mm) { + trace_printk("mmgrab to %d\n", atomic_read(&mm->mm_count) + 1); + } +#endif atomic_inc(&mm->mm_count); } @@ -45,6 +51,11 @@ static inline void mmdrop(struct mm_struct *mm) * required by the membarrier system call before returning to * user-space, after storing to rq->curr. */ +#if 0 + if (debug_mm == mm) { + trace_printk("mmdrop to %d\n", atomic_read(&mm->mm_count) - 1); + } +#endif if (unlikely(atomic_dec_and_test(&mm->mm_count))) __mmdrop(mm); } @@ -88,11 +99,22 @@ static inline bool mmget_still_valid(struct mm_struct *mm) */ static inline void mmget(struct mm_struct *mm) { +#if 0 + if (debug_mm == mm) { + trace_printk("mget %d\n", atomic_read(&mm->mm_users) + 1); + } +#endif atomic_inc(&mm->mm_users); } static inline bool mmget_not_zero(struct mm_struct *mm) { +#if 0 + if (debug_mm == mm) { + trace_printk("mmget_not_zero %d\n", + atomic_read(&mm->mm_users) + 1); + } +#endif return atomic_inc_not_zero(&mm->mm_users); } diff --git a/kernel/fork.c b/kernel/fork.c index b2b87d450b80..652533d5d4d6 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1076,6 +1076,12 @@ void mmput(struct mm_struct *mm) { might_sleep(); +#if 0 + if (debug_mm == mm) { + trace_printk("mmput after %d\n", + atomic_read(&mm->mm_users) - 1); + } +#endif if (atomic_dec_and_test(&mm->mm_users)) __mmput(mm); } @@ -1092,6 +1098,12 @@ static void mmput_async_fn(struct work_struct *work) void mmput_async(struct mm_struct *mm) { +#if 0 + if (debug_mm == mm) { + trace_printk("mmput to %d\n", + atomic_read(&mm->mm_users) - 1); + } +#endif if (atomic_dec_and_test(&mm->mm_users)) { INIT_WORK(&mm->async_put_work, mmput_async_fn); schedule_work(&mm->async_put_work); diff --git a/mm/init-mm.c b/mm/init-mm.c index a787a319211e..f6253a53a891 100644 --- a/mm/init-mm.c +++ b/mm/init-mm.c @@ -38,3 +38,6 @@ struct mm_struct init_mm = { .cpu_bitmap = { [BITS_TO_LONGS(NR_CPUS)] = 0}, INIT_MM_CONTEXT(init_mm) }; + +struct mm_struct *debug_mm = NULL; +EXPORT_SYMBOL_GPL(debug_mm);