Blame view

fs/seq_file.c 19.5 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
11
12
13
14
  #include <linux/seq_file.h>
  #include <linux/slab.h>
  
  #include <asm/uaccess.h>
  #include <asm/page.h>
e075f5915   KAMEZAWA Hiroyuki   seq_file: add seq...
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  
  /*
   * seq_files have a buffer which can may overflow. When this happens a larger
   * buffer is reallocated and all the data will be printed again.
   * The overflow state is true when m->count == m->size.
   */
  static bool seq_overflow(struct seq_file *m)
  {
  	return m->count == m->size;
  }
  
  static void seq_set_overflow(struct seq_file *m)
  {
  	m->count = m->size;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
34
35
36
37
38
39
40
41
  /**
   *	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...
42
   *	Returning SEQ_SKIP means "discard this element and move on".
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
   */
15ad7cdcf   Helge Deller   [PATCH] struct se...
44
  int seq_open(struct file *file, const struct seq_operations *op)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  {
1abe77b0f   Al Viro   [PATCH] allow cal...
46
47
48
49
50
51
52
53
  	struct seq_file *p = file->private_data;
  
  	if (!p) {
  		p = kmalloc(sizeof(*p), GFP_KERNEL);
  		if (!p)
  			return -ENOMEM;
  		file->private_data = p;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  	memset(p, 0, sizeof(*p));
0ac1759ab   Ingo Molnar   [PATCH] sem2mutex...
55
  	mutex_init(&p->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  	p->op = op;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
61
62
63
  
  	/*
  	 * 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...
64
65
66
67
68
69
70
71
72
73
  	/*
  	 * 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
74
75
76
  	return 0;
  }
  EXPORT_SYMBOL(seq_open);
33da8892a   Eric Biederman   seq_file: move tr...
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  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) {
  		m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
  		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;
  		}
e075f5915   KAMEZAWA Hiroyuki   seq_file: add seq...
107
  		if (seq_overflow(m))
33da8892a   Eric Biederman   seq_file: move tr...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  			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...
125
  	m->index = index;
33da8892a   Eric Biederman   seq_file: move tr...
126
127
128
129
130
131
132
133
  	return error;
  
  Eoverflow:
  	m->op->stop(m, p);
  	kfree(m->buf);
  	m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
  	return !m->buf ? -ENOMEM : -EAGAIN;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
  /**
   *	seq_read -	->read() method for sequential files.
67be2dd1b   Martin Waitz   [PATCH] DocBook: ...
136
137
138
139
   *	@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
140
141
142
143
144
   *
   *	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...
145
  	struct seq_file *m = file->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
149
150
  	size_t copied = 0;
  	loff_t pos;
  	size_t n;
  	void *p;
  	int err = 0;
0ac1759ab   Ingo Molnar   [PATCH] sem2mutex...
151
  	mutex_lock(&m->lock);
8f19d4729   Eric Biederman   seq_file: properl...
152

7904ac842   Earl Chew   seq_file: fix mis...
153
154
155
156
157
158
159
160
161
162
163
164
  	/*
  	 * 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;
8f19d4729   Eric Biederman   seq_file: properl...
165
166
  	/* Don't assume *ppos is where we left it */
  	if (unlikely(*ppos != m->read_pos)) {
8f19d4729   Eric Biederman   seq_file: properl...
167
168
169
170
171
172
173
174
175
  		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...
176
177
  		} else {
  			m->read_pos = *ppos;
8f19d4729   Eric Biederman   seq_file: properl...
178
179
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  	/* grab buffer if we didn't have one */
  	if (!m->buf) {
  		m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
  		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;
  		if (!m->count)
  			m->index++;
  		if (!size)
  			goto Done;
  	}
  	/* we need at least one record in buffer */
4cdfe84b5   Al Viro   [PATCH] deal with...
203
204
  	pos = m->index;
  	p = m->op->start(m, &pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
  	while (1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
207
208
209
  		err = PTR_ERR(p);
  		if (!p || IS_ERR(p))
  			break;
  		err = m->op->show(m, p);
521b5d0c4   Al Viro   [PATCH] teach seq...
210
  		if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
  			break;
521b5d0c4   Al Viro   [PATCH] teach seq...
212
213
  		if (unlikely(err))
  			m->count = 0;
4cdfe84b5   Al Viro   [PATCH] deal with...
214
215
216
217
218
  		if (unlikely(!m->count)) {
  			p = m->op->next(m, p, &pos);
  			m->index = pos;
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
221
222
223
224
225
226
227
  		if (m->count < m->size)
  			goto Fill;
  		m->op->stop(m, p);
  		kfree(m->buf);
  		m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
  		if (!m->buf)
  			goto Enomem;
  		m->count = 0;
  		m->version = 0;
4cdfe84b5   Al Viro   [PATCH] deal with...
228
229
  		pos = m->index;
  		p = m->op->start(m, &pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
  	}
  	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);
e075f5915   KAMEZAWA Hiroyuki   seq_file: add seq...
245
  		if (seq_overflow(m) || err) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  			m->count = offs;
521b5d0c4   Al Viro   [PATCH] teach seq...
247
248
  			if (likely(err <= 0))
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
  		}
  		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...
267
  	else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  		*ppos += copied;
8f19d4729   Eric Biederman   seq_file: properl...
269
270
  		m->read_pos += copied;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
  	file->f_version = m->version;
0ac1759ab   Ingo Molnar   [PATCH] sem2mutex...
272
  	mutex_unlock(&m->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
275
276
277
278
279
280
281
  	return copied;
  Enomem:
  	err = -ENOMEM;
  	goto Done;
  Efault:
  	err = -EFAULT;
  	goto Done;
  }
  EXPORT_SYMBOL(seq_read);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
  /**
   *	seq_lseek -	->llseek() method for sequential files.
67be2dd1b   Martin Waitz   [PATCH] DocBook: ...
284
285
286
   *	@file: the file in question
   *	@offset: new position
   *	@origin: 0 for absolute, 1 for relative position
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
290
291
   *
   *	Ready-made ->f_op->llseek()
   */
  loff_t seq_lseek(struct file *file, loff_t offset, int origin)
  {
8209e2f46   Joe Perches   fs/seq_file.c: Re...
292
  	struct seq_file *m = file->private_data;
16abef0e9   David Sterba   fs: use loff_t ty...
293
  	loff_t retval = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294

0ac1759ab   Ingo Molnar   [PATCH] sem2mutex...
295
  	mutex_lock(&m->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
299
300
301
302
303
  	m->version = file->f_version;
  	switch (origin) {
  		case 1:
  			offset += file->f_pos;
  		case 0:
  			if (offset < 0)
  				break;
  			retval = offset;
8f19d4729   Eric Biederman   seq_file: properl...
304
  			if (offset != m->read_pos) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
308
309
  				while ((retval=traverse(m, offset)) == -EAGAIN)
  					;
  				if (retval) {
  					/* with extreme prejudice... */
  					file->f_pos = 0;
8f19d4729   Eric Biederman   seq_file: properl...
310
  					m->read_pos = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
314
  					m->version = 0;
  					m->index = 0;
  					m->count = 0;
  				} else {
8f19d4729   Eric Biederman   seq_file: properl...
315
  					m->read_pos = offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
319
  					retval = file->f_pos = offset;
  				}
  			}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
  	file->f_version = m->version;
00c5746da   Alexey Dobriyan   mutex_unlock() la...
321
  	mutex_unlock(&m->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
325
326
327
328
  	return retval;
  }
  EXPORT_SYMBOL(seq_lseek);
  
  /**
   *	seq_release -	free the structures associated with sequential file.
   *	@file: file in question
0f7fc9e4d   Josef "Jeff" Sipek   [PATCH] VFS: chan...
329
   *	@inode: file->f_path.dentry->d_inode
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
332
333
334
335
   *
   *	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...
336
  	struct seq_file *m = file->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
  	kfree(m->buf);
  	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
   *	@esc with usual octal escape.  Returns 0 in case of success, -1 - in
   *	case of overflow.
   */
  int seq_escape(struct seq_file *m, const char *s, const char *esc)
  {
  	char *end = m->buf + m->size;
          char *p;
  	char c;
  
          for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) {
  		if (!strchr(esc, c)) {
  			*p++ = c;
  			continue;
  		}
  		if (p + 3 < end) {
  			*p++ = '\\';
  			*p++ = '0' + ((c & 0300) >> 6);
  			*p++ = '0' + ((c & 070) >> 3);
  			*p++ = '0' + (c & 07);
  			continue;
  		}
e075f5915   KAMEZAWA Hiroyuki   seq_file: add seq...
371
  		seq_set_overflow(m);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
374
375
376
377
  		return -1;
          }
  	m->count = p - m->buf;
          return 0;
  }
  EXPORT_SYMBOL(seq_escape);
a4808147d   Steven Whitehouse   seq_file: Add seq...
378
  int seq_vprintf(struct seq_file *m, const char *f, va_list args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
  	int len;
  
  	if (m->count < m->size) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
  		len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
386
387
388
  		if (m->count + len < m->size) {
  			m->count += len;
  			return 0;
  		}
  	}
e075f5915   KAMEZAWA Hiroyuki   seq_file: add seq...
389
  	seq_set_overflow(m);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
  	return -1;
  }
a4808147d   Steven Whitehouse   seq_file: Add seq...
392
393
394
395
396
397
398
399
400
401
402
403
404
  EXPORT_SYMBOL(seq_vprintf);
  
  int seq_printf(struct seq_file *m, const char *f, ...)
  {
  	int ret;
  	va_list args;
  
  	va_start(args, f);
  	ret = seq_vprintf(m, f, args);
  	va_end(args);
  
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
  EXPORT_SYMBOL(seq_printf);
74e2f334f   Török Edwin   vfs, seqfile: mak...
406
  /**
958086d17   Török Edwin   vfs, seqfile: fix...
407
408
409
410
   *	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...
411
412
413
414
415
416
   *
   *      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...
417
  char *mangle_path(char *s, const char *p, const char *esc)
6092d0481   Ram Pai   [patch 1/7] vfs: ...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
  {
  	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...
436
  EXPORT_SYMBOL(mangle_path);
6092d0481   Ram Pai   [patch 1/7] vfs: ...
437

52afeefb9   Arjan van de Ven   expand some comme...
438
439
440
441
442
443
444
445
  /**
   * 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: ...
446
   */
8c9379e97   Al Viro   constify seq_file...
447
  int seq_path(struct seq_file *m, const struct path *path, const char *esc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
  {
f84398068   Miklos Szeredi   vfs: seq_file: ad...
449
450
451
452
453
454
  	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
455
  		if (!IS_ERR(p)) {
f84398068   Miklos Szeredi   vfs: seq_file: ad...
456
457
458
  			char *end = mangle_path(buf, p, esc);
  			if (end)
  				res = end - buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
  		}
  	}
f84398068   Miklos Szeredi   vfs: seq_file: ad...
461
462
463
  	seq_commit(m, res);
  
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
465
  }
  EXPORT_SYMBOL(seq_path);
6092d0481   Ram Pai   [patch 1/7] vfs: ...
466
  /*
9d1bc6013   Miklos Szeredi   [patch 2/7] vfs: ...
467
   * Same as seq_path, but relative to supplied root.
9d1bc6013   Miklos Szeredi   [patch 2/7] vfs: ...
468
   */
8c9379e97   Al Viro   constify seq_file...
469
470
  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: ...
471
  {
f84398068   Miklos Szeredi   vfs: seq_file: ad...
472
473
474
475
476
  	char *buf;
  	size_t size = seq_get_buf(m, &buf);
  	int res = -ENAMETOOLONG;
  
  	if (size) {
9d1bc6013   Miklos Szeredi   [patch 2/7] vfs: ...
477
  		char *p;
f84398068   Miklos Szeredi   vfs: seq_file: ad...
478
  		p = __d_path(path, root, buf, size);
02125a826   Al Viro   fix apparmor dere...
479
480
  		if (!p)
  			return SEQ_SKIP;
f84398068   Miklos Szeredi   vfs: seq_file: ad...
481
  		res = PTR_ERR(p);
9d1bc6013   Miklos Szeredi   [patch 2/7] vfs: ...
482
  		if (!IS_ERR(p)) {
f84398068   Miklos Szeredi   vfs: seq_file: ad...
483
484
485
486
487
  			char *end = mangle_path(buf, p, esc);
  			if (end)
  				res = end - buf;
  			else
  				res = -ENAMETOOLONG;
9d1bc6013   Miklos Szeredi   [patch 2/7] vfs: ...
488
489
  		}
  	}
f84398068   Miklos Szeredi   vfs: seq_file: ad...
490
  	seq_commit(m, res);
02125a826   Al Viro   fix apparmor dere...
491
  	return res < 0 && res != -ENAMETOOLONG ? res : 0;
9d1bc6013   Miklos Szeredi   [patch 2/7] vfs: ...
492
493
494
  }
  
  /*
6092d0481   Ram Pai   [patch 1/7] vfs: ...
495
496
   * returns the path of the 'dentry' from the root of its filesystem.
   */
8c9379e97   Al Viro   constify seq_file...
497
  int seq_dentry(struct seq_file *m, struct dentry *dentry, const char *esc)
6092d0481   Ram Pai   [patch 1/7] vfs: ...
498
  {
f84398068   Miklos Szeredi   vfs: seq_file: ad...
499
500
501
502
503
504
  	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: ...
505
  		if (!IS_ERR(p)) {
f84398068   Miklos Szeredi   vfs: seq_file: ad...
506
507
508
  			char *end = mangle_path(buf, p, esc);
  			if (end)
  				res = end - buf;
6092d0481   Ram Pai   [patch 1/7] vfs: ...
509
510
  		}
  	}
f84398068   Miklos Szeredi   vfs: seq_file: ad...
511
512
513
  	seq_commit(m, res);
  
  	return res;
6092d0481   Ram Pai   [patch 1/7] vfs: ...
514
  }
cb78a0ce6   Rusty Russell   bitmap: fix seq_b...
515
516
  int seq_bitmap(struct seq_file *m, const unsigned long *bits,
  				   unsigned int nr_bits)
50ac2d694   Alexey Dobriyan   seq_file: add seq...
517
  {
85dd030ed   Lai Jiangshan   seq_file: don't c...
518
519
520
521
522
523
524
  	if (m->count < m->size) {
  		int len = bitmap_scnprintf(m->buf + m->count,
  				m->size - m->count, bits, nr_bits);
  		if (m->count + len < m->size) {
  			m->count += len;
  			return 0;
  		}
50ac2d694   Alexey Dobriyan   seq_file: add seq...
525
  	}
e075f5915   KAMEZAWA Hiroyuki   seq_file: add seq...
526
  	seq_set_overflow(m);
50ac2d694   Alexey Dobriyan   seq_file: add seq...
527
528
  	return -1;
  }
85dd030ed   Lai Jiangshan   seq_file: don't c...
529
  EXPORT_SYMBOL(seq_bitmap);
50ac2d694   Alexey Dobriyan   seq_file: add seq...
530

af76aba00   Rusty Russell   cpumask: fix seq_...
531
  int seq_bitmap_list(struct seq_file *m, const unsigned long *bits,
3eda20118   Lai Jiangshan   seq_file: add seq...
532
533
534
535
536
537
538
539
540
541
  		unsigned int nr_bits)
  {
  	if (m->count < m->size) {
  		int len = bitmap_scnlistprintf(m->buf + m->count,
  				m->size - m->count, bits, nr_bits);
  		if (m->count + len < m->size) {
  			m->count += len;
  			return 0;
  		}
  	}
e075f5915   KAMEZAWA Hiroyuki   seq_file: add seq...
542
  	seq_set_overflow(m);
3eda20118   Lai Jiangshan   seq_file: add seq...
543
544
545
  	return -1;
  }
  EXPORT_SYMBOL(seq_bitmap_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
575
576
577
578
579
580
581
582
583
  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);
  
  int single_release(struct inode *inode, struct file *file)
  {
15ad7cdcf   Helge Deller   [PATCH] struct se...
584
  	const struct seq_operations *op = ((struct seq_file *)file->private_data)->op;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
  	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...
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
  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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
  int seq_putc(struct seq_file *m, char c)
  {
  	if (m->count < m->size) {
  		m->buf[m->count++] = c;
  		return 0;
  	}
  	return -1;
  }
  EXPORT_SYMBOL(seq_putc);
  
  int seq_puts(struct seq_file *m, const char *s)
  {
  	int len = strlen(s);
  	if (m->count + len < m->size) {
  		memcpy(m->buf + m->count, s, len);
  		m->count += len;
  		return 0;
  	}
e075f5915   KAMEZAWA Hiroyuki   seq_file: add seq...
650
  	seq_set_overflow(m);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
653
  	return -1;
  }
  EXPORT_SYMBOL(seq_puts);
bcf67e162   Pavel Emelianov   Make common helpe...
654

1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
655
656
657
658
659
660
661
662
663
664
665
666
667
668
  /*
   * A helper routine for putting decimal numbers without rich format of printf().
   * only 'unsigned long long' is supported.
   * This routine will put one byte delimiter + number into seq_file.
   * 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.
   */
  int seq_put_decimal_ull(struct seq_file *m, char delimiter,
  			unsigned long long num)
  {
  	int len;
  
  	if (m->count + 2 >= m->size) /* we'll write 2 bytes at least */
  		goto overflow;
bda7bad62   KAMEZAWA Hiroyuki   procfs: speed up ...
669
670
  	if (delimiter)
  		m->buf[m->count++] = delimiter;
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
671
672
673
674
675
676
677
678
679
680
681
682
  
  	if (num < 10) {
  		m->buf[m->count++] = num + '0';
  		return 0;
  	}
  
  	len = num_to_str(m->buf + m->count, m->size - m->count, num);
  	if (!len)
  		goto overflow;
  	m->count += len;
  	return 0;
  overflow:
e075f5915   KAMEZAWA Hiroyuki   seq_file: add seq...
683
  	seq_set_overflow(m);
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
684
685
686
  	return -1;
  }
  EXPORT_SYMBOL(seq_put_decimal_ull);
bda7bad62   KAMEZAWA Hiroyuki   procfs: speed up ...
687
688
689
690
691
  int seq_put_decimal_ll(struct seq_file *m, char delimiter,
  			long long num)
  {
  	if (num < 0) {
  		if (m->count + 3 >= m->size) {
e075f5915   KAMEZAWA Hiroyuki   seq_file: add seq...
692
  			seq_set_overflow(m);
bda7bad62   KAMEZAWA Hiroyuki   procfs: speed up ...
693
694
695
696
697
698
699
700
701
702
703
  			return -1;
  		}
  		if (delimiter)
  			m->buf[m->count++] = delimiter;
  		num = -num;
  		delimiter = '-';
  	}
  	return seq_put_decimal_ull(m, delimiter, num);
  
  }
  EXPORT_SYMBOL(seq_put_decimal_ll);
0b923606e   Peter Oberparleiter   seq_file: add fun...
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
  /**
   * 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...
719
  	seq_set_overflow(seq);
0b923606e   Peter Oberparleiter   seq_file: add fun...
720
721
722
  	return -1;
  }
  EXPORT_SYMBOL(seq_write);
bcf67e162   Pavel Emelianov   Make common helpe...
723
724
725
726
727
728
729
730
731
732
  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...
733
734
735
736
737
738
739
740
741
  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...
742
743
744
745
746
747
748
749
750
751
  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...
752
  EXPORT_SYMBOL(seq_list_next);
66655de6d   Li Zefan   seq_file: Add hel...
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
  
  /**
   * 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...
793
   * @ppos: the current position
66655de6d   Li Zefan   seq_file: Add hel...
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
   *
   * 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...
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
  
  /**
   * 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...
859
   * @ppos: the current position
1cc523271   stephen hemminger   seq_file: add RCU...
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
   *
   * 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);