function tracing: fix wrong position computing of stack_trace

Impact: make output of stack_trace complete if buffer overruns

When read buffer overruns, the output of stack_trace isn't complete.

When printing records with seq_printf in t_show, if the read buffer
has overruned by the current record, then this record won't be
printed to user space through read buffer, it will just be dropped in
this printing.

When next printing, t_start should return the "*pos"th record, which
is the one dropped by previous printing, but it just returns
(m->private + *pos)th record.

Here we use a more sane method to implement seq_operations which can
be found in kernel code. Thus we needn't initialize m->private.

About testing, it's not easy to overrun read buffer, but we can use
seq_printf to print more padding bytes in t_show, then it's easy to
check whether or not records are lost.

This commit has been tested on both condition of overrun and non
overrun.

Signed-off-by: Liming Wang <liming.wang@windriver.com>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>

authored by Liming Wang and committed by Ingo Molnar 522a110b ed313489

+15 -9
+15 -9
kernel/trace/trace_stack.c
··· 184 184 static void * 185 185 t_next(struct seq_file *m, void *v, loff_t *pos) 186 186 { 187 - long i = (long)m->private; 187 + long i; 188 188 189 189 (*pos)++; 190 190 191 - i++; 191 + if (v == SEQ_START_TOKEN) 192 + i = 0; 193 + else { 194 + i = *(long *)v; 195 + i++; 196 + } 192 197 193 198 if (i >= max_stack_trace.nr_entries || 194 199 stack_dump_trace[i] == ULONG_MAX) ··· 206 201 207 202 static void *t_start(struct seq_file *m, loff_t *pos) 208 203 { 209 - void *t = &m->private; 204 + void *t = SEQ_START_TOKEN; 210 205 loff_t l = 0; 211 206 212 207 local_irq_disable(); 213 208 __raw_spin_lock(&max_stack_lock); 209 + 210 + if (*pos == 0) 211 + return SEQ_START_TOKEN; 214 212 215 213 for (; t && l < *pos; t = t_next(m, t, &l)) 216 214 ; ··· 243 235 244 236 static int t_show(struct seq_file *m, void *v) 245 237 { 246 - long i = *(long *)v; 238 + long i; 247 239 int size; 248 240 249 - if (i < 0) { 241 + if (v == SEQ_START_TOKEN) { 250 242 seq_printf(m, " Depth Size Location" 251 243 " (%d entries)\n" 252 244 " ----- ---- --------\n", 253 245 max_stack_trace.nr_entries); 254 246 return 0; 255 247 } 248 + 249 + i = *(long *)v; 256 250 257 251 if (i >= max_stack_trace.nr_entries || 258 252 stack_dump_trace[i] == ULONG_MAX) ··· 285 275 int ret; 286 276 287 277 ret = seq_open(file, &stack_trace_seq_ops); 288 - if (!ret) { 289 - struct seq_file *m = file->private_data; 290 - m->private = (void *)-1; 291 - } 292 278 293 279 return ret; 294 280 }