Re: [PATCH] Fix x86 initialization for {hard, soft}irq_ctx

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




----- Original Message -----
> 
> ----- Original Message -----
> >
> > Current code is setting {hard,soft}irq_ctx[] to (irq_ctx **), because
> > per_cpu symbol itself is pointer of specified type (irq_ctx *).
> >
> > But, I wonder how this works in past, the code is expecting
> > {hard,soft}_ctx[] are (irq_ctx *). This fixes by deref per_cpu in
> > initialization, and set expected pointers.
> >
> > Tested on i386 v3.10.
> >
> 
> You are correct -- apparently it never did work.
> 
> The reason why I never noticed with RHEL kernels is that up until
> linux-2.6.29,
> the IRQ stacks were declared as a static NR_CPUS-bounded array:
>   
>   #ifdef CONFIG_4KSTACKS
>   /*
>    * per-CPU IRQ handling contexts (thread information and stack)
>    */
>   union irq_ctx {
>           struct thread_info      tinfo;
>           u32                     stack[THREAD_SIZE/sizeof(u32)];
>   };
>   
>   static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly;
>   static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly;
>   
>   static char softirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss;
>   static char hardirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss;
>   
>   
> Then in linux-2.6.30, they were changed to be per-cpu variables:
>   
>   #ifdef CONFIG_4KSTACKS
>   /*
>    * per-CPU IRQ handling contexts (thread information and stack)
>    */
>   union irq_ctx {
>           struct thread_info      tinfo;
>           u32                     stack[THREAD_SIZE/sizeof(u32)];
>   } __attribute__((aligned(PAGE_SIZE)));
>   
>   static DEFINE_PER_CPU(union irq_ctx *, hardirq_ctx);
>   static DEFINE_PER_CPU(union irq_ctx *, softirq_ctx);
>   
>   static DEFINE_PER_CPU_PAGE_ALIGNED(union irq_ctx, hardirq_stack);
>   static DEFINE_PER_CPU_PAGE_ALIGNED(union irq_ctx, softirq_stack);
>   
> We never ran into the bug in 32-bit x86 RHEL6 (2.6.32-based) kernels because
> we did not configure CONFIG_4KSTACKS.
> 
> Later on, the CONFIG_4KSTACKS restriction looks like it was removed, but we
> stopped supporting 32-bit x86 in RHEL7.  And nobody ever reported it from any
> other x86 kernel sources.
> 
> I also note that in linux-3.15 the data structure name and variables were
> changed to:
>  
>   struct irq_stack {
>           u32                     stack[THREAD_SIZE/sizeof(u32)];
>   } __aligned(THREAD_SIZE);
> 
>   DECLARE_PER_CPU(struct irq_stack *, hardirq_stack);
>   DECLARE_PER_CPU(struct irq_stack *, softirq_stack);
> 
> So your patch would need more work for 3.15 and later kernels.
> 
> Thanks,
>   Dave

Hi Ogawa,

Please review the attached update to your patch, which adds support for 
the irq_ctx-to-irq_stack transition.

Thanks,
  Dave
diff --git a/task.c b/task.c
index 95d9130..661c104 100644
--- a/task.c
+++ b/task.c
@@ -567,13 +567,24 @@ irqstacks_init(void)
 
 	thread_info_buf = GETBUF(SIZE(irq_ctx));
 
-	if ((hard_sp = per_cpu_symbol_search("per_cpu__hardirq_ctx"))) {
+	if ((hard_sp = per_cpu_symbol_search("per_cpu__hardirq_ctx")) ||
+	    (hard_sp = per_cpu_symbol_search("per_cpu__hardirq_stack"))) {
 		if ((kt->flags & SMP) && (kt->flags & PER_CPU_OFF)) {
 			for (i = 0; i < NR_CPUS; i++) {
+				ulong ptr;
+
 				if (!kt->__per_cpu_offset[i])
 					continue;
-				tt->hardirq_ctx[i] = hard_sp->value +
-					kt->__per_cpu_offset[i];
+				ptr = hard_sp->value + kt->__per_cpu_offset[i];
+
+				if (!readmem(ptr, KVADDR, &ptr,
+					     sizeof(void *), "hardirq ctx",
+					     RETURN_ON_ERROR)) {
+					error(INFO, "cannot read hardirq_ctx[%d] at %lx\n",
+					      i, ptr);
+					continue;
+				}
+				tt->hardirq_ctx[i] = ptr;
 			}
 		} else 
 			tt->hardirq_ctx[0] = hard_sp->value;
@@ -585,29 +596,42 @@ irqstacks_init(void)
 	} else 
 		error(WARNING, "cannot determine hardirq_ctx addresses\n");
 
-	for (i = 0; i < NR_CPUS; i++) {
-        	if (!(tt->hardirq_ctx[i]))
-                        continue;
+	if (MEMBER_EXISTS("irq_ctx", "tinfo")) {
+		for (i = 0; i < NR_CPUS; i++) {
+			if (!(tt->hardirq_ctx[i]))
+				continue;
 
-                if (!readmem(tt->hardirq_ctx[i], KVADDR, thread_info_buf, 
-		    SIZE(irq_ctx), "hardirq thread_union", 
-		    RETURN_ON_ERROR)) {
-                	error(INFO, "cannot read hardirq_ctx[%d] at %lx\n",
-                            	i, tt->hardirq_ctx[i]);
-                        continue;
-                }
+			if (!readmem(tt->hardirq_ctx[i], KVADDR, thread_info_buf, 
+			    SIZE(irq_ctx), "hardirq thread_union", 
+			    RETURN_ON_ERROR)) {
+				error(INFO, "cannot read hardirq_ctx[%d] at %lx\n",
+					i, tt->hardirq_ctx[i]);
+				continue;
+			}
 
-                tt->hardirq_tasks[i] = 
-			ULONG(thread_info_buf+OFFSET(thread_info_task));
+			tt->hardirq_tasks[i] = 
+				ULONG(thread_info_buf+OFFSET(thread_info_task));
+		}
 	}
 
-	if ((soft_sp = per_cpu_symbol_search("per_cpu__softirq_ctx"))) {
+	if ((soft_sp = per_cpu_symbol_search("per_cpu__softirq_ctx")) ||
+	    (soft_sp = per_cpu_symbol_search("per_cpu__softirq_stack"))) {
 		if ((kt->flags & SMP) && (kt->flags & PER_CPU_OFF)) {
 			for (i = 0; i < NR_CPUS; i++) {
+				ulong ptr;
+
 				if (!kt->__per_cpu_offset[i])
 					continue;
-				tt->softirq_ctx[i] = soft_sp->value +
-					kt->__per_cpu_offset[i];
+				ptr = soft_sp->value + kt->__per_cpu_offset[i];
+
+				if (!readmem(ptr, KVADDR, &ptr,
+					     sizeof(void *), "softirq ctx",
+					     RETURN_ON_ERROR)) {
+					error(INFO, "cannot read softirq_ctx[%d] at %lx\n",
+					      i, ptr);
+					continue;
+				}
+				tt->softirq_ctx[i] = ptr;
 			}
 		} else 
 			 tt->softirq_ctx[0] = soft_sp->value;
@@ -619,21 +643,23 @@ irqstacks_init(void)
 	} else
 		error(WARNING, "cannot determine softirq_ctx addresses\n");
 
-        for (i = 0; i < NR_CPUS; i++) {
-                if (!(tt->softirq_ctx[i]))
-                        continue;
-
-                if (!readmem(tt->softirq_ctx[i], KVADDR, thread_info_buf,
-                    SIZE(irq_ctx), "softirq thread_union",
-                    RETURN_ON_ERROR)) {
-			error(INFO, "cannot read softirq_ctx[%d] at %lx\n",
-                       		i, tt->hardirq_ctx[i]);
-                    	continue;
-                }
-
-                tt->softirq_tasks[i] =
-                        ULONG(thread_info_buf+OFFSET(thread_info_task));
-        }
+	if (MEMBER_EXISTS("irq_ctx", "tinfo")) {
+	        for (i = 0; i < NR_CPUS; i++) {
+			if (!(tt->softirq_ctx[i]))
+				continue;
+	
+			if (!readmem(tt->softirq_ctx[i], KVADDR, thread_info_buf,
+			    SIZE(irq_ctx), "softirq thread_union",
+			    RETURN_ON_ERROR)) {
+				error(INFO, "cannot read softirq_ctx[%d] at %lx\n",
+					i, tt->hardirq_ctx[i]);
+				continue;
+			}
+	
+			tt->softirq_tasks[i] =
+				ULONG(thread_info_buf+OFFSET(thread_info_task));
+		}
+	}
 
 
         tt->flags |= IRQSTACKS;
diff --git a/x86.c b/x86.c
index 54ce7a5..27bf0ea 100644
--- a/x86.c
+++ b/x86.c
@@ -1963,6 +1963,8 @@ x86_init(int when)
 		STRUCT_SIZE_INIT(e820map, "e820map");
 		STRUCT_SIZE_INIT(e820entry, "e820entry");
 		STRUCT_SIZE_INIT(irq_ctx, "irq_ctx");
+		if (!VALID_STRUCT(irq_ctx))
+			STRUCT_SIZE_INIT(irq_ctx, "irq_stack");
 		MEMBER_OFFSET_INIT(e820map_nr_map, "e820map", "nr_map");
 		MEMBER_OFFSET_INIT(e820entry_addr, "e820entry", "addr");
 		MEMBER_OFFSET_INIT(e820entry_size, "e820entry", "size");
--
Crash-utility mailing list
Crash-utility@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/crash-utility

[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux