diff options
Diffstat (limited to 'mm/vmalloc.c')
| -rw-r--r-- | mm/vmalloc.c | 55 | 
1 files changed, 42 insertions, 13 deletions
diff --git a/mm/vmalloc.c b/mm/vmalloc.c index aee1f61727a..bda6cef5b97 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -1304,7 +1304,14 @@ static void insert_vmalloc_vmlist(struct vm_struct *vm)  {  	struct vm_struct *tmp, **p; +	/* +	 * Before removing VM_UNLIST, +	 * we should make sure that vm has proper values. +	 * Pair with smp_rmb() in show_numa_info(). +	 */ +	smp_wmb();  	vm->flags &= ~VM_UNLIST; +  	write_lock(&vmlist_lock);  	for (p = &vmlist; (tmp = *p) != NULL; p = &tmp->next) {  		if (tmp->addr >= vm->addr) @@ -2542,19 +2549,19 @@ void pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms)  #ifdef CONFIG_PROC_FS  static void *s_start(struct seq_file *m, loff_t *pos) -	__acquires(&vmlist_lock) +	__acquires(&vmap_area_lock)  {  	loff_t n = *pos; -	struct vm_struct *v; +	struct vmap_area *va; -	read_lock(&vmlist_lock); -	v = vmlist; -	while (n > 0 && v) { +	spin_lock(&vmap_area_lock); +	va = list_entry((&vmap_area_list)->next, typeof(*va), list); +	while (n > 0 && &va->list != &vmap_area_list) {  		n--; -		v = v->next; +		va = list_entry(va->list.next, typeof(*va), list);  	} -	if (!n) -		return v; +	if (!n && &va->list != &vmap_area_list) +		return va;  	return NULL; @@ -2562,16 +2569,20 @@ static void *s_start(struct seq_file *m, loff_t *pos)  static void *s_next(struct seq_file *m, void *p, loff_t *pos)  { -	struct vm_struct *v = p; +	struct vmap_area *va = p, *next;  	++*pos; -	return v->next; +	next = list_entry(va->list.next, typeof(*va), list); +	if (&next->list != &vmap_area_list) +		return next; + +	return NULL;  }  static void s_stop(struct seq_file *m, void *p) -	__releases(&vmlist_lock) +	__releases(&vmap_area_lock)  { -	read_unlock(&vmlist_lock); +	spin_unlock(&vmap_area_lock);  }  static void show_numa_info(struct seq_file *m, struct vm_struct *v) @@ -2582,6 +2593,11 @@ static void show_numa_info(struct seq_file *m, struct vm_struct *v)  		if (!counters)  			return; +		/* Pair with smp_wmb() in insert_vmalloc_vmlist() */ +		smp_rmb(); +		if (v->flags & VM_UNLIST) +			return; +  		memset(counters, 0, nr_node_ids * sizeof(unsigned int));  		for (nr = 0; nr < v->nr_pages; nr++) @@ -2595,7 +2611,20 @@ static void show_numa_info(struct seq_file *m, struct vm_struct *v)  static int s_show(struct seq_file *m, void *p)  { -	struct vm_struct *v = p; +	struct vmap_area *va = p; +	struct vm_struct *v; + +	if (va->flags & (VM_LAZY_FREE | VM_LAZY_FREEING)) +		return 0; + +	if (!(va->flags & VM_VM_AREA)) { +		seq_printf(m, "0x%pK-0x%pK %7ld vm_map_ram\n", +			(void *)va->va_start, (void *)va->va_end, +					va->va_end - va->va_start); +		return 0; +	} + +	v = va->vm;  	seq_printf(m, "0x%pK-0x%pK %7ld",  		v->addr, v->addr + v->size, v->size);  |