Blame view

fs/seq_file.c 23.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
  /*
   * linux/fs/seq_file.c
   *
   * helper functions for making synthetic files from sequences of records.
   * initial implementation -- AV, Oct 2001.
   */
  
  #include <linux/fs.h>
630d9c472   Paul Gortmaker   fs: reduce the us...
9
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
  #include <linux/seq_file.h>
058504edd   Heiko Carstens   fs/seq_file: fall...
11
  #include <linux/vmalloc.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
  #include <linux/slab.h>
adb37c4c6   Eric W. Biederman   userns: Make seq_...
13
  #include <linux/cred.h>
058504edd   Heiko Carstens   fs/seq_file: fall...
14
  #include <linux/mm.h>
37607102c   Andy Shevchenko   seq_file: provide...
15
  #include <linux/printk.h>
25c6bb76e   Andy Shevchenko   seq_file: reuse s...
16
  #include <linux/string_helpers.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17

7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
18
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
  #include <asm/page.h>
e075f5915   KAMEZAWA Hiroyuki   seq_file: add seq...
20
21
22
23
  static void seq_set_overflow(struct seq_file *m)
  {
  	m->count = m->size;
  }
058504edd   Heiko Carstens   fs/seq_file: fall...
24
25
26
  static void *seq_buf_alloc(unsigned long size)
  {
  	void *buf;
0f930902e   Greg Thelen   fs, seqfile: alwa...
27
  	gfp_t gfp = GFP_KERNEL;
058504edd   Heiko Carstens   fs/seq_file: fall...
28

5cec38ac8   David Rientjes   fs, seq_file: fal...
29
  	/*
0f930902e   Greg Thelen   fs, seqfile: alwa...
30
31
32
33
  	 * For high order allocations, use __GFP_NORETRY to avoid oom-killing -
  	 * it's better to fall back to vmalloc() than to kill things.  For small
  	 * allocations, just use GFP_KERNEL which will oom kill, thus no need
  	 * for vmalloc fallback.
5cec38ac8   David Rientjes   fs, seq_file: fal...
34
  	 */
0f930902e   Greg Thelen   fs, seqfile: alwa...
35
36
37
  	if (size > PAGE_SIZE)
  		gfp |= __GFP_NORETRY | __GFP_NOWARN;
  	buf = kmalloc(size, gfp);
058504edd   Heiko Carstens   fs/seq_file: fall...
38
39
40
41
  	if (!buf && size > PAGE_SIZE)
  		buf = vmalloc(size);
  	return buf;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
48
49
50
51
52
53
  /**
   *	seq_open -	initialize sequential file
   *	@file: file we initialize
   *	@op: method table describing the sequence
   *
   *	seq_open() sets @file, associating it with a sequence described
   *	by @op.  @op->start() sets the iterator up and returns the first
   *	element of sequence. @op->stop() shuts it down.  @op->next()
   *	returns the next element of sequence.  @op->show() prints element
   *	into the buffer.  In case of error ->start() and ->next() return
   *	ERR_PTR(error).  In the end of sequence they return %NULL. ->show()
   *	returns 0 in case of success and negative number in case of error.
521b5d0c4   Al Viro   [PATCH] teach seq...
54
   *	Returning SEQ_SKIP means "discard this element and move on".
460b865e5   Yann Droneaud   fs: document seq_...
55
56
   *	Note: seq_open() will allocate a struct seq_file and store its
   *	pointer in @file->private_data. This pointer should not be modified.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
   */
15ad7cdcf   Helge Deller   [PATCH] struct se...
58
  int seq_open(struct file *file, const struct seq_operations *op)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  {
189f9841d   Yann Droneaud   fs: allocate stru...
60
61
62
63
64
65
66
67
68
  	struct seq_file *p;
  
  	WARN_ON(file->private_data);
  
  	p = kzalloc(sizeof(*p), GFP_KERNEL);
  	if (!p)
  		return -ENOMEM;
  
  	file->private_data = p;
1abe77b0f   Al Viro   [PATCH] allow cal...
69

0ac1759ab   Ingo Molnar   [PATCH] sem2mutex...
70
  	mutex_init(&p->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  	p->op = op;
34dbbcdbf   Linus Torvalds   Make file credent...
72
73
74
75
  
  	// No refcounting: the lifetime of 'p' is constrained
  	// to the lifetime of the file.
  	p->file = file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
81
82
  
  	/*
  	 * Wrappers around seq_open(e.g. swaps_open) need to be
  	 * aware of this. If they set f_version themselves, they
  	 * should call seq_open first and then set f_version.
  	 */
  	file->f_version = 0;
8f19d4729   Eric Biederman   seq_file: properl...
83
84
85
86
87
88
89
90
91
92
  	/*
  	 * seq_files support lseek() and pread().  They do not implement
  	 * write() at all, but we clear FMODE_PWRITE here for historical
  	 * reasons.
  	 *
  	 * If a client of seq_files a) implements file.write() and b) wishes to
  	 * support pwrite() then that client will need to implement its own
  	 * file.open() which calls seq_open() and then sets FMODE_PWRITE.
  	 */
  	file->f_mode &= ~FMODE_PWRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
95
  	return 0;
  }
  EXPORT_SYMBOL(seq_open);
33da8892a   Eric Biederman   seq_file: move tr...
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  static int traverse(struct seq_file *m, loff_t offset)
  {
  	loff_t pos = 0, index;
  	int error = 0;
  	void *p;
  
  	m->version = 0;
  	index = 0;
  	m->count = m->from = 0;
  	if (!offset) {
  		m->index = index;
  		return 0;
  	}
  	if (!m->buf) {
058504edd   Heiko Carstens   fs/seq_file: fall...
110
  		m->buf = seq_buf_alloc(m->size = PAGE_SIZE);
33da8892a   Eric Biederman   seq_file: move tr...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  		if (!m->buf)
  			return -ENOMEM;
  	}
  	p = m->op->start(m, &index);
  	while (p) {
  		error = PTR_ERR(p);
  		if (IS_ERR(p))
  			break;
  		error = m->op->show(m, p);
  		if (error < 0)
  			break;
  		if (unlikely(error)) {
  			error = 0;
  			m->count = 0;
  		}
1f33c41c0   Joe Perches   seq_file: Rename ...
126
  		if (seq_has_overflowed(m))
33da8892a   Eric Biederman   seq_file: move tr...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  			goto Eoverflow;
  		if (pos + m->count > offset) {
  			m->from = offset - pos;
  			m->count -= m->from;
  			m->index = index;
  			break;
  		}
  		pos += m->count;
  		m->count = 0;
  		if (pos == offset) {
  			index++;
  			m->index = index;
  			break;
  		}
  		p = m->op->next(m, p, &index);
  	}
  	m->op->stop(m, p);
f01d1d546   Alexey Dobriyan   seq_file: fix big...
144
  	m->index = index;
33da8892a   Eric Biederman   seq_file: move tr...
145
146
147
148
  	return error;
  
  Eoverflow:
  	m->op->stop(m, p);
058504edd   Heiko Carstens   fs/seq_file: fall...
149
  	kvfree(m->buf);
801a76050   Al Viro   seq_file: always ...
150
  	m->count = 0;
058504edd   Heiko Carstens   fs/seq_file: fall...
151
  	m->buf = seq_buf_alloc(m->size <<= 1);
33da8892a   Eric Biederman   seq_file: move tr...
152
153
  	return !m->buf ? -ENOMEM : -EAGAIN;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
  /**
   *	seq_read -	->read() method for sequential files.
67be2dd1b   Martin Waitz   [PATCH] DocBook: ...
156
157
158
159
   *	@file: the file to read from
   *	@buf: the buffer to read to
   *	@size: the maximum number of bytes to read
   *	@ppos: the current position in the file
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
162
163
164
   *
   *	Ready-made ->f_op->read()
   */
  ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
  {
8209e2f46   Joe Perches   fs/seq_file.c: Re...
165
  	struct seq_file *m = file->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
168
169
170
  	size_t copied = 0;
  	loff_t pos;
  	size_t n;
  	void *p;
  	int err = 0;
0ac1759ab   Ingo Molnar   [PATCH] sem2mutex...
171
  	mutex_lock(&m->lock);
8f19d4729   Eric Biederman   seq_file: properl...
172

7904ac842   Earl Chew   seq_file: fix mis...
173
174
175
176
177
178
179
180
181
182
183
184
  	/*
  	 * seq_file->op->..m_start/m_stop/m_next may do special actions
  	 * or optimisations based on the file->f_version, so we want to
  	 * pass the file->f_version to those methods.
  	 *
  	 * seq_file->version is just copy of f_version, and seq_file
  	 * methods can treat it simply as file version.
  	 * It is copied in first and copied out after all operations.
  	 * It is convenient to have it as  part of structure to avoid the
  	 * need of passing another argument to all the seq_file methods.
  	 */
  	m->version = file->f_version;
e522751d6   Tomasz Majchrzak   seq_file: reset i...
185
186
187
188
189
190
  	/*
  	 * if request is to read from zero offset, reset iterator to first
  	 * record as it might have been already advanced by previous requests
  	 */
  	if (*ppos == 0)
  		m->index = 0;
8f19d4729   Eric Biederman   seq_file: properl...
191
192
  	/* Don't assume *ppos is where we left it */
  	if (unlikely(*ppos != m->read_pos)) {
8f19d4729   Eric Biederman   seq_file: properl...
193
194
195
196
197
198
199
200
201
  		while ((err = traverse(m, *ppos)) == -EAGAIN)
  			;
  		if (err) {
  			/* With prejudice... */
  			m->read_pos = 0;
  			m->version = 0;
  			m->index = 0;
  			m->count = 0;
  			goto Done;
7904ac842   Earl Chew   seq_file: fix mis...
202
203
  		} else {
  			m->read_pos = *ppos;
8f19d4729   Eric Biederman   seq_file: properl...
204
205
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
207
  	/* grab buffer if we didn't have one */
  	if (!m->buf) {
058504edd   Heiko Carstens   fs/seq_file: fall...
208
  		m->buf = seq_buf_alloc(m->size = PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  		if (!m->buf)
  			goto Enomem;
  	}
  	/* if not empty - flush it first */
  	if (m->count) {
  		n = min(m->count, size);
  		err = copy_to_user(buf, m->buf + m->from, n);
  		if (err)
  			goto Efault;
  		m->count -= n;
  		m->from += n;
  		size -= n;
  		buf += n;
  		copied += n;
088bf2ff5   Vegard Nossum   fs/seq_file: fix ...
223
224
  		if (!m->count) {
  			m->from = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  			m->index++;
088bf2ff5   Vegard Nossum   fs/seq_file: fix ...
226
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
230
  		if (!size)
  			goto Done;
  	}
  	/* we need at least one record in buffer */
4cdfe84b5   Al Viro   [PATCH] deal with...
231
232
  	pos = m->index;
  	p = m->op->start(m, &pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  	while (1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
236
237
  		err = PTR_ERR(p);
  		if (!p || IS_ERR(p))
  			break;
  		err = m->op->show(m, p);
521b5d0c4   Al Viro   [PATCH] teach seq...
238
  		if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
  			break;
521b5d0c4   Al Viro   [PATCH] teach seq...
240
241
  		if (unlikely(err))
  			m->count = 0;
4cdfe84b5   Al Viro   [PATCH] deal with...
242
243
244
245
246
  		if (unlikely(!m->count)) {
  			p = m->op->next(m, p, &pos);
  			m->index = pos;
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
249
  		if (m->count < m->size)
  			goto Fill;
  		m->op->stop(m, p);
058504edd   Heiko Carstens   fs/seq_file: fall...
250
  		kvfree(m->buf);
801a76050   Al Viro   seq_file: always ...
251
  		m->count = 0;
058504edd   Heiko Carstens   fs/seq_file: fall...
252
  		m->buf = seq_buf_alloc(m->size <<= 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
  		if (!m->buf)
  			goto Enomem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  		m->version = 0;
4cdfe84b5   Al Viro   [PATCH] deal with...
256
257
  		pos = m->index;
  		p = m->op->start(m, &pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
  	}
  	m->op->stop(m, p);
  	m->count = 0;
  	goto Done;
  Fill:
  	/* they want more? let's try to get some more */
  	while (m->count < size) {
  		size_t offs = m->count;
  		loff_t next = pos;
  		p = m->op->next(m, p, &next);
  		if (!p || IS_ERR(p)) {
  			err = PTR_ERR(p);
  			break;
  		}
  		err = m->op->show(m, p);
1f33c41c0   Joe Perches   seq_file: Rename ...
273
  		if (seq_has_overflowed(m) || err) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  			m->count = offs;
521b5d0c4   Al Viro   [PATCH] teach seq...
275
276
  			if (likely(err <= 0))
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
  		}
  		pos = next;
  	}
  	m->op->stop(m, p);
  	n = min(m->count, size);
  	err = copy_to_user(buf, m->buf, n);
  	if (err)
  		goto Efault;
  	copied += n;
  	m->count -= n;
  	if (m->count)
  		m->from = n;
  	else
  		pos++;
  	m->index = pos;
  Done:
  	if (!copied)
  		copied = err;
8f19d4729   Eric Biederman   seq_file: properl...
295
  	else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  		*ppos += copied;
8f19d4729   Eric Biederman   seq_file: properl...
297
298
  		m->read_pos += copied;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  	file->f_version = m->version;
0ac1759ab   Ingo Molnar   [PATCH] sem2mutex...
300
  	mutex_unlock(&m->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
304
305
306
307
308
309
  	return copied;
  Enomem:
  	err = -ENOMEM;
  	goto Done;
  Efault:
  	err = -EFAULT;
  	goto Done;
  }
  EXPORT_SYMBOL(seq_read);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
  /**
   *	seq_lseek -	->llseek() method for sequential files.
67be2dd1b   Martin Waitz   [PATCH] DocBook: ...
312
313
   *	@file: the file in question
   *	@offset: new position
254adaa46   Randy Dunlap   seq_file: fix new...
314
   *	@whence: 0 for absolute, 1 for relative position
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
317
   *
   *	Ready-made ->f_op->llseek()
   */
965c8e59c   Andrew Morton   lseek: the "whenc...
318
  loff_t seq_lseek(struct file *file, loff_t offset, int whence)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  {
8209e2f46   Joe Perches   fs/seq_file.c: Re...
320
  	struct seq_file *m = file->private_data;
16abef0e9   David Sterba   fs: use loff_t ty...
321
  	loff_t retval = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322

0ac1759ab   Ingo Molnar   [PATCH] sem2mutex...
323
  	mutex_lock(&m->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  	m->version = file->f_version;
965c8e59c   Andrew Morton   lseek: the "whenc...
325
  	switch (whence) {
5e62adef9   Andrew Morton   fs/seq_file.c:seq...
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
  	case SEEK_CUR:
  		offset += file->f_pos;
  	case SEEK_SET:
  		if (offset < 0)
  			break;
  		retval = offset;
  		if (offset != m->read_pos) {
  			while ((retval = traverse(m, offset)) == -EAGAIN)
  				;
  			if (retval) {
  				/* with extreme prejudice... */
  				file->f_pos = 0;
  				m->read_pos = 0;
  				m->version = 0;
  				m->index = 0;
  				m->count = 0;
  			} else {
  				m->read_pos = offset;
  				retval = file->f_pos = offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
  			}
05e16745c   Gu Zheng   seq_file: always ...
346
347
  		} else {
  			file->f_pos = offset;
5e62adef9   Andrew Morton   fs/seq_file.c:seq...
348
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
  	file->f_version = m->version;
00c5746da   Alexey Dobriyan   mutex_unlock() la...
351
  	mutex_unlock(&m->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
355
356
357
358
  	return retval;
  }
  EXPORT_SYMBOL(seq_lseek);
  
  /**
   *	seq_release -	free the structures associated with sequential file.
   *	@file: file in question
6131ffaa1   Al Viro   more file_inode()...
359
   *	@inode: its inode
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
362
363
364
365
   *
   *	Frees the structures associated with sequential file; can be used
   *	as ->f_op->release() if you don't have private data to destroy.
   */
  int seq_release(struct inode *inode, struct file *file)
  {
8209e2f46   Joe Perches   fs/seq_file.c: Re...
366
  	struct seq_file *m = file->private_data;
058504edd   Heiko Carstens   fs/seq_file: fall...
367
  	kvfree(m->buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
370
371
372
373
374
375
376
377
378
379
  	kfree(m);
  	return 0;
  }
  EXPORT_SYMBOL(seq_release);
  
  /**
   *	seq_escape -	print string into buffer, escaping some characters
   *	@m:	target buffer
   *	@s:	string
   *	@esc:	set of characters that need escaping
   *
   *	Puts string into buffer, replacing each occurrence of character from
6798a8caa   Joe Perches   fs/seq_file: conv...
380
381
   *	@esc with usual octal escape.
   *	Use seq_has_overflowed() to check for errors.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
   */
6798a8caa   Joe Perches   fs/seq_file: conv...
383
  void seq_escape(struct seq_file *m, const char *s, const char *esc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
  {
25c6bb76e   Andy Shevchenko   seq_file: reuse s...
385
386
387
  	char *buf;
  	size_t size = seq_get_buf(m, &buf);
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388

25c6bb76e   Andy Shevchenko   seq_file: reuse s...
389
390
  	ret = string_escape_str(s, buf, size, ESCAPE_OCTAL, esc);
  	seq_commit(m, ret < size ? ret : -1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
  }
  EXPORT_SYMBOL(seq_escape);
6798a8caa   Joe Perches   fs/seq_file: conv...
393
  void seq_vprintf(struct seq_file *m, const char *f, va_list args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
  	int len;
  
  	if (m->count < m->size) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  		len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
400
  		if (m->count + len < m->size) {
  			m->count += len;
6798a8caa   Joe Perches   fs/seq_file: conv...
401
  			return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
403
  		}
  	}
e075f5915   KAMEZAWA Hiroyuki   seq_file: add seq...
404
  	seq_set_overflow(m);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
  }
a4808147d   Steven Whitehouse   seq_file: Add seq...
406
  EXPORT_SYMBOL(seq_vprintf);
6798a8caa   Joe Perches   fs/seq_file: conv...
407
  void seq_printf(struct seq_file *m, const char *f, ...)
a4808147d   Steven Whitehouse   seq_file: Add seq...
408
  {
a4808147d   Steven Whitehouse   seq_file: Add seq...
409
410
411
  	va_list args;
  
  	va_start(args, f);
6798a8caa   Joe Perches   fs/seq_file: conv...
412
  	seq_vprintf(m, f, args);
a4808147d   Steven Whitehouse   seq_file: Add seq...
413
  	va_end(args);
a4808147d   Steven Whitehouse   seq_file: Add seq...
414
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
  EXPORT_SYMBOL(seq_printf);
74e2f334f   Török Edwin   vfs, seqfile: mak...
416
  /**
958086d17   Török Edwin   vfs, seqfile: fix...
417
418
419
420
   *	mangle_path -	mangle and copy path to buffer beginning
   *	@s: buffer start
   *	@p: beginning of path in above buffer
   *	@esc: set of characters that need escaping
74e2f334f   Török Edwin   vfs, seqfile: mak...
421
422
423
424
425
426
   *
   *      Copy the path from @p to @s, replacing each occurrence of character from
   *      @esc with usual octal escape.
   *      Returns pointer past last written character in @s, or NULL in case of
   *      failure.
   */
8c9379e97   Al Viro   constify seq_file...
427
  char *mangle_path(char *s, const char *p, const char *esc)
6092d0481   Ram Pai   [patch 1/7] vfs: ...
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
  {
  	while (s <= p) {
  		char c = *p++;
  		if (!c) {
  			return s;
  		} else if (!strchr(esc, c)) {
  			*s++ = c;
  		} else if (s + 4 > p) {
  			break;
  		} else {
  			*s++ = '\\';
  			*s++ = '0' + ((c & 0300) >> 6);
  			*s++ = '0' + ((c & 070) >> 3);
  			*s++ = '0' + (c & 07);
  		}
  	}
  	return NULL;
  }
604094f46   Ingo Molnar   vfs, seqfile: exp...
446
  EXPORT_SYMBOL(mangle_path);
6092d0481   Ram Pai   [patch 1/7] vfs: ...
447

52afeefb9   Arjan van de Ven   expand some comme...
448
449
450
451
452
453
454
455
  /**
   * seq_path - seq_file interface to print a pathname
   * @m: the seq_file handle
   * @path: the struct path to print
   * @esc: set of characters to escape in the output
   *
   * return the absolute path of 'path', as represented by the
   * dentry / mnt pair in the path parameter.
6092d0481   Ram Pai   [patch 1/7] vfs: ...
456
   */
8c9379e97   Al Viro   constify seq_file...
457
  int seq_path(struct seq_file *m, const struct path *path, const char *esc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
  {
f84398068   Miklos Szeredi   vfs: seq_file: ad...
459
460
461
462
463
464
  	char *buf;
  	size_t size = seq_get_buf(m, &buf);
  	int res = -1;
  
  	if (size) {
  		char *p = d_path(path, buf, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
  		if (!IS_ERR(p)) {
f84398068   Miklos Szeredi   vfs: seq_file: ad...
466
467
468
  			char *end = mangle_path(buf, p, esc);
  			if (end)
  				res = end - buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
  		}
  	}
f84398068   Miklos Szeredi   vfs: seq_file: ad...
471
472
473
  	seq_commit(m, res);
  
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
  }
  EXPORT_SYMBOL(seq_path);
2726d5662   Miklos Szeredi   vfs: add seq_file...
476
477
478
479
480
481
482
483
484
485
486
487
488
  /**
   * seq_file_path - seq_file interface to print a pathname of a file
   * @m: the seq_file handle
   * @file: the struct file to print
   * @esc: set of characters to escape in the output
   *
   * return the absolute path to the file.
   */
  int seq_file_path(struct seq_file *m, struct file *file, const char *esc)
  {
  	return seq_path(m, &file->f_path, esc);
  }
  EXPORT_SYMBOL(seq_file_path);
6092d0481   Ram Pai   [patch 1/7] vfs: ...
489
  /*
9d1bc6013   Miklos Szeredi   [patch 2/7] vfs: ...
490
   * Same as seq_path, but relative to supplied root.
9d1bc6013   Miklos Szeredi   [patch 2/7] vfs: ...
491
   */
8c9379e97   Al Viro   constify seq_file...
492
493
  int seq_path_root(struct seq_file *m, const struct path *path,
  		  const struct path *root, const char *esc)
9d1bc6013   Miklos Szeredi   [patch 2/7] vfs: ...
494
  {
f84398068   Miklos Szeredi   vfs: seq_file: ad...
495
496
497
498
499
  	char *buf;
  	size_t size = seq_get_buf(m, &buf);
  	int res = -ENAMETOOLONG;
  
  	if (size) {
9d1bc6013   Miklos Szeredi   [patch 2/7] vfs: ...
500
  		char *p;
f84398068   Miklos Szeredi   vfs: seq_file: ad...
501
  		p = __d_path(path, root, buf, size);
02125a826   Al Viro   fix apparmor dere...
502
503
  		if (!p)
  			return SEQ_SKIP;
f84398068   Miklos Szeredi   vfs: seq_file: ad...
504
  		res = PTR_ERR(p);
9d1bc6013   Miklos Szeredi   [patch 2/7] vfs: ...
505
  		if (!IS_ERR(p)) {
f84398068   Miklos Szeredi   vfs: seq_file: ad...
506
507
508
509
510
  			char *end = mangle_path(buf, p, esc);
  			if (end)
  				res = end - buf;
  			else
  				res = -ENAMETOOLONG;
9d1bc6013   Miklos Szeredi   [patch 2/7] vfs: ...
511
512
  		}
  	}
f84398068   Miklos Szeredi   vfs: seq_file: ad...
513
  	seq_commit(m, res);
02125a826   Al Viro   fix apparmor dere...
514
  	return res < 0 && res != -ENAMETOOLONG ? res : 0;
9d1bc6013   Miklos Szeredi   [patch 2/7] vfs: ...
515
516
517
  }
  
  /*
6092d0481   Ram Pai   [patch 1/7] vfs: ...
518
519
   * returns the path of the 'dentry' from the root of its filesystem.
   */
8c9379e97   Al Viro   constify seq_file...
520
  int seq_dentry(struct seq_file *m, struct dentry *dentry, const char *esc)
6092d0481   Ram Pai   [patch 1/7] vfs: ...
521
  {
f84398068   Miklos Szeredi   vfs: seq_file: ad...
522
523
524
525
526
527
  	char *buf;
  	size_t size = seq_get_buf(m, &buf);
  	int res = -1;
  
  	if (size) {
  		char *p = dentry_path(dentry, buf, size);
6092d0481   Ram Pai   [patch 1/7] vfs: ...
528
  		if (!IS_ERR(p)) {
f84398068   Miklos Szeredi   vfs: seq_file: ad...
529
530
531
  			char *end = mangle_path(buf, p, esc);
  			if (end)
  				res = end - buf;
6092d0481   Ram Pai   [patch 1/7] vfs: ...
532
533
  		}
  	}
f84398068   Miklos Szeredi   vfs: seq_file: ad...
534
535
536
  	seq_commit(m, res);
  
  	return res;
6092d0481   Ram Pai   [patch 1/7] vfs: ...
537
  }
c8d3fe028   Omar Sandoval   Btrfs: show subvo...
538
  EXPORT_SYMBOL(seq_dentry);
6092d0481   Ram Pai   [patch 1/7] vfs: ...
539

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
  static void *single_start(struct seq_file *p, loff_t *pos)
  {
  	return NULL + (*pos == 0);
  }
  
  static void *single_next(struct seq_file *p, void *v, loff_t *pos)
  {
  	++*pos;
  	return NULL;
  }
  
  static void single_stop(struct seq_file *p, void *v)
  {
  }
  
  int single_open(struct file *file, int (*show)(struct seq_file *, void *),
  		void *data)
  {
  	struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL);
  	int res = -ENOMEM;
  
  	if (op) {
  		op->start = single_start;
  		op->next = single_next;
  		op->stop = single_stop;
  		op->show = show;
  		res = seq_open(file, op);
  		if (!res)
  			((struct seq_file *)file->private_data)->private = data;
  		else
  			kfree(op);
  	}
  	return res;
  }
  EXPORT_SYMBOL(single_open);
2043f495c   Al Viro   new helper: singl...
575
576
577
  int single_open_size(struct file *file, int (*show)(struct seq_file *, void *),
  		void *data, size_t size)
  {
058504edd   Heiko Carstens   fs/seq_file: fall...
578
  	char *buf = seq_buf_alloc(size);
2043f495c   Al Viro   new helper: singl...
579
580
581
582
583
  	int ret;
  	if (!buf)
  		return -ENOMEM;
  	ret = single_open(file, show, data);
  	if (ret) {
058504edd   Heiko Carstens   fs/seq_file: fall...
584
  		kvfree(buf);
2043f495c   Al Viro   new helper: singl...
585
586
587
588
589
590
591
  		return ret;
  	}
  	((struct seq_file *)file->private_data)->buf = buf;
  	((struct seq_file *)file->private_data)->size = size;
  	return 0;
  }
  EXPORT_SYMBOL(single_open_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
  int single_release(struct inode *inode, struct file *file)
  {
15ad7cdcf   Helge Deller   [PATCH] struct se...
594
  	const struct seq_operations *op = ((struct seq_file *)file->private_data)->op;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
  	int res = seq_release(inode, file);
  	kfree(op);
  	return res;
  }
  EXPORT_SYMBOL(single_release);
  
  int seq_release_private(struct inode *inode, struct file *file)
  {
  	struct seq_file *seq = file->private_data;
  
  	kfree(seq->private);
  	seq->private = NULL;
  	return seq_release(inode, file);
  }
  EXPORT_SYMBOL(seq_release_private);
39699037a   Pavel Emelyanov   [FS] seq_file: In...
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
  void *__seq_open_private(struct file *f, const struct seq_operations *ops,
  		int psize)
  {
  	int rc;
  	void *private;
  	struct seq_file *seq;
  
  	private = kzalloc(psize, GFP_KERNEL);
  	if (private == NULL)
  		goto out;
  
  	rc = seq_open(f, ops);
  	if (rc < 0)
  		goto out_free;
  
  	seq = f->private_data;
  	seq->private = private;
  	return private;
  
  out_free:
  	kfree(private);
  out:
  	return NULL;
  }
  EXPORT_SYMBOL(__seq_open_private);
  
  int seq_open_private(struct file *filp, const struct seq_operations *ops,
  		int psize)
  {
  	return __seq_open_private(filp, ops, psize) ? 0 : -ENOMEM;
  }
  EXPORT_SYMBOL(seq_open_private);
6798a8caa   Joe Perches   fs/seq_file: conv...
642
  void seq_putc(struct seq_file *m, char c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
  {
6798a8caa   Joe Perches   fs/seq_file: conv...
644
645
646
647
  	if (m->count >= m->size)
  		return;
  
  	m->buf[m->count++] = c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
  }
  EXPORT_SYMBOL(seq_putc);
6798a8caa   Joe Perches   fs/seq_file: conv...
650
  void seq_puts(struct seq_file *m, const char *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
  {
  	int len = strlen(s);
6798a8caa   Joe Perches   fs/seq_file: conv...
653
654
655
656
  
  	if (m->count + len >= m->size) {
  		seq_set_overflow(m);
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
  	}
6798a8caa   Joe Perches   fs/seq_file: conv...
658
659
  	memcpy(m->buf + m->count, s, len);
  	m->count += len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
661
  }
  EXPORT_SYMBOL(seq_puts);
bcf67e162   Pavel Emelianov   Make common helpe...
662

1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
663
664
665
  /*
   * A helper routine for putting decimal numbers without rich format of printf().
   * only 'unsigned long long' is supported.
75ba1d07f   Joe Perches   seq/proc: modify ...
666
   * This routine will put strlen(delimiter) + number into seq_file.
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
667
668
669
   * This routine is very quick when you show lots of numbers.
   * In usual cases, it will be better to use seq_printf(). It's easier to read.
   */
75ba1d07f   Joe Perches   seq/proc: modify ...
670
  void seq_put_decimal_ull(struct seq_file *m, const char *delimiter,
6798a8caa   Joe Perches   fs/seq_file: conv...
671
  			 unsigned long long num)
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
672
673
674
675
676
  {
  	int len;
  
  	if (m->count + 2 >= m->size) /* we'll write 2 bytes at least */
  		goto overflow;
75ba1d07f   Joe Perches   seq/proc: modify ...
677
678
679
680
681
682
683
684
685
  	len = strlen(delimiter);
  	if (m->count + len >= m->size)
  		goto overflow;
  
  	memcpy(m->buf + m->count, delimiter, len);
  	m->count += len;
  
  	if (m->count + 1 >= m->size)
  		goto overflow;
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
686
687
688
  
  	if (num < 10) {
  		m->buf[m->count++] = num + '0';
6798a8caa   Joe Perches   fs/seq_file: conv...
689
  		return;
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
690
691
692
693
694
  	}
  
  	len = num_to_str(m->buf + m->count, m->size - m->count, num);
  	if (!len)
  		goto overflow;
75ba1d07f   Joe Perches   seq/proc: modify ...
695

1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
696
  	m->count += len;
6798a8caa   Joe Perches   fs/seq_file: conv...
697
  	return;
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
698
  overflow:
e075f5915   KAMEZAWA Hiroyuki   seq_file: add seq...
699
  	seq_set_overflow(m);
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
700
701
  }
  EXPORT_SYMBOL(seq_put_decimal_ull);
75ba1d07f   Joe Perches   seq/proc: modify ...
702
  void seq_put_decimal_ll(struct seq_file *m, const char *delimiter, long long num)
bda7bad62   KAMEZAWA Hiroyuki   procfs: speed up ...
703
  {
75ba1d07f   Joe Perches   seq/proc: modify ...
704
705
706
707
708
709
710
711
712
713
714
715
716
717
  	int len;
  
  	if (m->count + 3 >= m->size) /* we'll write 2 bytes at least */
  		goto overflow;
  
  	len = strlen(delimiter);
  	if (m->count + len >= m->size)
  		goto overflow;
  
  	memcpy(m->buf + m->count, delimiter, len);
  	m->count += len;
  
  	if (m->count + 2 >= m->size)
  		goto overflow;
bda7bad62   KAMEZAWA Hiroyuki   procfs: speed up ...
718
  	if (num < 0) {
75ba1d07f   Joe Perches   seq/proc: modify ...
719
  		m->buf[m->count++] = '-';
bda7bad62   KAMEZAWA Hiroyuki   procfs: speed up ...
720
  		num = -num;
bda7bad62   KAMEZAWA Hiroyuki   procfs: speed up ...
721
  	}
75ba1d07f   Joe Perches   seq/proc: modify ...
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
  
  	if (num < 10) {
  		m->buf[m->count++] = num + '0';
  		return;
  	}
  
  	len = num_to_str(m->buf + m->count, m->size - m->count, num);
  	if (!len)
  		goto overflow;
  
  	m->count += len;
  	return;
  
  overflow:
  	seq_set_overflow(m);
bda7bad62   KAMEZAWA Hiroyuki   procfs: speed up ...
737
738
  }
  EXPORT_SYMBOL(seq_put_decimal_ll);
0b923606e   Peter Oberparleiter   seq_file: add fun...
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
  /**
   * seq_write - write arbitrary data to buffer
   * @seq: seq_file identifying the buffer to which data should be written
   * @data: data address
   * @len: number of bytes
   *
   * Return 0 on success, non-zero otherwise.
   */
  int seq_write(struct seq_file *seq, const void *data, size_t len)
  {
  	if (seq->count + len < seq->size) {
  		memcpy(seq->buf + seq->count, data, len);
  		seq->count += len;
  		return 0;
  	}
e075f5915   KAMEZAWA Hiroyuki   seq_file: add seq...
754
  	seq_set_overflow(seq);
0b923606e   Peter Oberparleiter   seq_file: add fun...
755
756
757
  	return -1;
  }
  EXPORT_SYMBOL(seq_write);
839cc2a94   Tetsuo Handa   seq_file: introdu...
758
759
760
761
762
763
764
765
766
767
768
769
770
771
  /**
   * seq_pad - write padding spaces to buffer
   * @m: seq_file identifying the buffer to which data should be written
   * @c: the byte to append after padding if non-zero
   */
  void seq_pad(struct seq_file *m, char c)
  {
  	int size = m->pad_until - m->count;
  	if (size > 0)
  		seq_printf(m, "%*s", size, "");
  	if (c)
  		seq_putc(m, c);
  }
  EXPORT_SYMBOL(seq_pad);
37607102c   Andy Shevchenko   seq_file: provide...
772
773
774
775
776
777
778
  /* A complete analogue of print_hex_dump() */
  void seq_hex_dump(struct seq_file *m, const char *prefix_str, int prefix_type,
  		  int rowsize, int groupsize, const void *buf, size_t len,
  		  bool ascii)
  {
  	const u8 *ptr = buf;
  	int i, linelen, remaining = len;
8b91a318e   Andy Shevchenko   fs/seq_file: use ...
779
780
  	char *buffer;
  	size_t size;
37607102c   Andy Shevchenko   seq_file: provide...
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
  	int ret;
  
  	if (rowsize != 16 && rowsize != 32)
  		rowsize = 16;
  
  	for (i = 0; i < len && !seq_has_overflowed(m); i += rowsize) {
  		linelen = min(remaining, rowsize);
  		remaining -= rowsize;
  
  		switch (prefix_type) {
  		case DUMP_PREFIX_ADDRESS:
  			seq_printf(m, "%s%p: ", prefix_str, ptr + i);
  			break;
  		case DUMP_PREFIX_OFFSET:
  			seq_printf(m, "%s%.8x: ", prefix_str, i);
  			break;
  		default:
  			seq_printf(m, "%s", prefix_str);
  			break;
  		}
8b91a318e   Andy Shevchenko   fs/seq_file: use ...
801
  		size = seq_get_buf(m, &buffer);
37607102c   Andy Shevchenko   seq_file: provide...
802
  		ret = hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
8b91a318e   Andy Shevchenko   fs/seq_file: use ...
803
804
805
806
807
  					 buffer, size, ascii);
  		seq_commit(m, ret < size ? ret : -1);
  
  		seq_putc(m, '
  ');
37607102c   Andy Shevchenko   seq_file: provide...
808
809
810
  	}
  }
  EXPORT_SYMBOL(seq_hex_dump);
bcf67e162   Pavel Emelianov   Make common helpe...
811
812
813
814
815
816
817
818
819
820
  struct list_head *seq_list_start(struct list_head *head, loff_t pos)
  {
  	struct list_head *lh;
  
  	list_for_each(lh, head)
  		if (pos-- == 0)
  			return lh;
  
  	return NULL;
  }
bcf67e162   Pavel Emelianov   Make common helpe...
821
822
823
824
825
826
827
828
829
  EXPORT_SYMBOL(seq_list_start);
  
  struct list_head *seq_list_start_head(struct list_head *head, loff_t pos)
  {
  	if (!pos)
  		return head;
  
  	return seq_list_start(head, pos - 1);
  }
bcf67e162   Pavel Emelianov   Make common helpe...
830
831
832
833
834
835
836
837
838
839
  EXPORT_SYMBOL(seq_list_start_head);
  
  struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos)
  {
  	struct list_head *lh;
  
  	lh = ((struct list_head *)v)->next;
  	++*ppos;
  	return lh == head ? NULL : lh;
  }
bcf67e162   Pavel Emelianov   Make common helpe...
840
  EXPORT_SYMBOL(seq_list_next);
66655de6d   Li Zefan   seq_file: Add hel...
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
  
  /**
   * seq_hlist_start - start an iteration of a hlist
   * @head: the head of the hlist
   * @pos:  the start position of the sequence
   *
   * Called at seq_file->op->start().
   */
  struct hlist_node *seq_hlist_start(struct hlist_head *head, loff_t pos)
  {
  	struct hlist_node *node;
  
  	hlist_for_each(node, head)
  		if (pos-- == 0)
  			return node;
  	return NULL;
  }
  EXPORT_SYMBOL(seq_hlist_start);
  
  /**
   * seq_hlist_start_head - start an iteration of a hlist
   * @head: the head of the hlist
   * @pos:  the start position of the sequence
   *
   * Called at seq_file->op->start(). Call this function if you want to
   * print a header at the top of the output.
   */
  struct hlist_node *seq_hlist_start_head(struct hlist_head *head, loff_t pos)
  {
  	if (!pos)
  		return SEQ_START_TOKEN;
  
  	return seq_hlist_start(head, pos - 1);
  }
  EXPORT_SYMBOL(seq_hlist_start_head);
  
  /**
   * seq_hlist_next - move to the next position of the hlist
   * @v:    the current iterator
   * @head: the head of the hlist
138860b95   Randy Dunlap   seq_file: fix new...
881
   * @ppos: the current position
66655de6d   Li Zefan   seq_file: Add hel...
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
   *
   * Called at seq_file->op->next().
   */
  struct hlist_node *seq_hlist_next(void *v, struct hlist_head *head,
  				  loff_t *ppos)
  {
  	struct hlist_node *node = v;
  
  	++*ppos;
  	if (v == SEQ_START_TOKEN)
  		return head->first;
  	else
  		return node->next;
  }
  EXPORT_SYMBOL(seq_hlist_next);
1cc523271   stephen hemminger   seq_file: add RCU...
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
  
  /**
   * seq_hlist_start_rcu - start an iteration of a hlist protected by RCU
   * @head: the head of the hlist
   * @pos:  the start position of the sequence
   *
   * Called at seq_file->op->start().
   *
   * This list-traversal primitive may safely run concurrently with
   * the _rcu list-mutation primitives such as hlist_add_head_rcu()
   * as long as the traversal is guarded by rcu_read_lock().
   */
  struct hlist_node *seq_hlist_start_rcu(struct hlist_head *head,
  				       loff_t pos)
  {
  	struct hlist_node *node;
  
  	__hlist_for_each_rcu(node, head)
  		if (pos-- == 0)
  			return node;
  	return NULL;
  }
  EXPORT_SYMBOL(seq_hlist_start_rcu);
  
  /**
   * seq_hlist_start_head_rcu - start an iteration of a hlist protected by RCU
   * @head: the head of the hlist
   * @pos:  the start position of the sequence
   *
   * Called at seq_file->op->start(). Call this function if you want to
   * print a header at the top of the output.
   *
   * This list-traversal primitive may safely run concurrently with
   * the _rcu list-mutation primitives such as hlist_add_head_rcu()
   * as long as the traversal is guarded by rcu_read_lock().
   */
  struct hlist_node *seq_hlist_start_head_rcu(struct hlist_head *head,
  					    loff_t pos)
  {
  	if (!pos)
  		return SEQ_START_TOKEN;
  
  	return seq_hlist_start_rcu(head, pos - 1);
  }
  EXPORT_SYMBOL(seq_hlist_start_head_rcu);
  
  /**
   * seq_hlist_next_rcu - move to the next position of the hlist protected by RCU
   * @v:    the current iterator
   * @head: the head of the hlist
138860b95   Randy Dunlap   seq_file: fix new...
947
   * @ppos: the current position
1cc523271   stephen hemminger   seq_file: add RCU...
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
   *
   * Called at seq_file->op->next().
   *
   * This list-traversal primitive may safely run concurrently with
   * the _rcu list-mutation primitives such as hlist_add_head_rcu()
   * as long as the traversal is guarded by rcu_read_lock().
   */
  struct hlist_node *seq_hlist_next_rcu(void *v,
  				      struct hlist_head *head,
  				      loff_t *ppos)
  {
  	struct hlist_node *node = v;
  
  	++*ppos;
  	if (v == SEQ_START_TOKEN)
  		return rcu_dereference(head->first);
  	else
  		return rcu_dereference(node->next);
  }
  EXPORT_SYMBOL(seq_hlist_next_rcu);
0bc77381c   Jeff Layton   seq_file: add seq...
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
  
  /**
   * seq_hlist_start_precpu - start an iteration of a percpu hlist array
   * @head: pointer to percpu array of struct hlist_heads
   * @cpu:  pointer to cpu "cursor"
   * @pos:  start position of sequence
   *
   * Called at seq_file->op->start().
   */
  struct hlist_node *
  seq_hlist_start_percpu(struct hlist_head __percpu *head, int *cpu, loff_t pos)
  {
  	struct hlist_node *node;
  
  	for_each_possible_cpu(*cpu) {
  		hlist_for_each(node, per_cpu_ptr(head, *cpu)) {
  			if (pos-- == 0)
  				return node;
  		}
  	}
  	return NULL;
  }
  EXPORT_SYMBOL(seq_hlist_start_percpu);
  
  /**
   * seq_hlist_next_percpu - move to the next position of the percpu hlist array
   * @v:    pointer to current hlist_node
   * @head: pointer to percpu array of struct hlist_heads
   * @cpu:  pointer to cpu "cursor"
   * @pos:  start position of sequence
   *
   * Called at seq_file->op->next().
   */
  struct hlist_node *
  seq_hlist_next_percpu(void *v, struct hlist_head __percpu *head,
  			int *cpu, loff_t *pos)
  {
  	struct hlist_node *node = v;
  
  	++*pos;
  
  	if (node->next)
  		return node->next;
  
  	for (*cpu = cpumask_next(*cpu, cpu_possible_mask); *cpu < nr_cpu_ids;
  	     *cpu = cpumask_next(*cpu, cpu_possible_mask)) {
  		struct hlist_head *bucket = per_cpu_ptr(head, *cpu);
  
  		if (!hlist_empty(bucket))
  			return bucket->first;
  	}
  	return NULL;
  }
  EXPORT_SYMBOL(seq_hlist_next_percpu);