Blame view

fs/afs/proc.c 14.2 KB
ec26815ad   David Howells   [AFS]: Clean up t...
1
  /* /proc interface for AFS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
   *
   * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells (dhowells@redhat.com)
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version
   * 2 of the License, or (at your option) any later version.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
  #include <linux/slab.h>
  #include <linux/module.h>
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
15
  #include <linux/sched.h>
7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
16
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  #include "internal.h"
5b86d4ff5   David Howells   afs: Implement ne...
18
  static inline struct afs_net *afs_seq2net(struct seq_file *m)
f044c8847   David Howells   afs: Lay the grou...
19
  {
5b86d4ff5   David Howells   afs: Implement ne...
20
  	return afs_net(seq_file_net(m));
f044c8847   David Howells   afs: Lay the grou...
21
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22

5b86d4ff5   David Howells   afs: Implement ne...
23
  static inline struct afs_net *afs_seq2net_single(struct seq_file *m)
f044c8847   David Howells   afs: Lay the grou...
24
  {
5b86d4ff5   David Howells   afs: Implement ne...
25
  	return afs_net(seq_file_single_net(m));
f044c8847   David Howells   afs: Lay the grou...
26
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  /*
5d9de25d9   David Howells   afs: Rearrange fs...
29
   * Display the list of cells known to the namespace.
f06916895   David Howells   afs: Rearrange fs...
30
31
32
33
   */
  static int afs_proc_cells_show(struct seq_file *m, void *v)
  {
  	struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
f06916895   David Howells   afs: Rearrange fs...
34

6b3944e42   David Howells   afs: Fix cell pro...
35
  	if (v == SEQ_START_TOKEN) {
f06916895   David Howells   afs: Rearrange fs...
36
37
38
39
40
41
42
43
44
45
46
  		/* display header on line 1 */
  		seq_puts(m, "USE NAME
  ");
  		return 0;
  	}
  
  	/* display one cell per line on subsequent lines */
  	seq_printf(m, "%3u %s
  ", atomic_read(&cell->usage), cell->name);
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
fe342cf77   David Howells   afs: Fix checker ...
48
  	__acquires(rcu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  {
989782dcd   David Howells   afs: Overhaul cel...
50
  	rcu_read_lock();
6b3944e42   David Howells   afs: Fix cell pro...
51
  	return seq_hlist_start_head_rcu(&afs_seq2net(m)->proc_cells, *_pos);
ec26815ad   David Howells   [AFS]: Clean up t...
52
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53

f044c8847   David Howells   afs: Lay the grou...
54
  static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  {
6b3944e42   David Howells   afs: Fix cell pro...
56
  	return seq_hlist_next_rcu(v, &afs_seq2net(m)->proc_cells, pos);
ec26815ad   David Howells   [AFS]: Clean up t...
57
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58

f044c8847   David Howells   afs: Lay the grou...
59
  static void afs_proc_cells_stop(struct seq_file *m, void *v)
fe342cf77   David Howells   afs: Fix checker ...
60
  	__releases(rcu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  {
989782dcd   David Howells   afs: Overhaul cel...
62
  	rcu_read_unlock();
ec26815ad   David Howells   [AFS]: Clean up t...
63
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64

5d9de25d9   David Howells   afs: Rearrange fs...
65
66
67
68
69
70
  static const struct seq_operations afs_proc_cells_ops = {
  	.start	= afs_proc_cells_start,
  	.next	= afs_proc_cells_next,
  	.stop	= afs_proc_cells_stop,
  	.show	= afs_proc_cells_show,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
   * handle writes to /proc/fs/afs/cells
   * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
   */
5b86d4ff5   David Howells   afs: Implement ne...
75
  static int afs_proc_cells_write(struct file *file, char *buf, size_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
  {
5b86d4ff5   David Howells   afs: Implement ne...
77
78
79
  	struct seq_file *m = file->private_data;
  	struct afs_net *net = afs_seq2net(m);
  	char *name, *args;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
  	/* trim to first NL */
5b86d4ff5   David Howells   afs: Implement ne...
82
83
  	name = memchr(buf, '
  ', size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
86
87
  	if (name)
  		*name = 0;
  
  	/* split into command, name and argslist */
5b86d4ff5   David Howells   afs: Implement ne...
88
  	name = strchr(buf, ' ');
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
91
92
93
94
95
96
97
  	if (!name)
  		goto inval;
  	do {
  		*name++ = 0;
  	} while(*name == ' ');
  	if (!*name)
  		goto inval;
  
  	args = strchr(name, ' ');
ecfe951f0   David Howells   afs: Fix cell spe...
98
99
100
101
102
103
104
  	if (args) {
  		do {
  			*args++ = 0;
  		} while(*args == ' ');
  		if (!*args)
  			goto inval;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
  
  	/* determine command to perform */
5b86d4ff5   David Howells   afs: Implement ne...
107
  	_debug("cmd=%s name=%s args=%s", buf, name, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108

5b86d4ff5   David Howells   afs: Implement ne...
109
  	if (strcmp(buf, "add") == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  		struct afs_cell *cell;
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
111

989782dcd   David Howells   afs: Overhaul cel...
112
  		cell = afs_lookup_cell(net, name, strlen(name), args, true);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
113
114
  		if (IS_ERR(cell)) {
  			ret = PTR_ERR(cell);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
  			goto done;
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
116
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117

17814aef5   David Howells   afs: Don't over-i...
118
119
  		if (test_and_set_bit(AFS_CELL_FL_NO_GC, &cell->flags))
  			afs_put_cell(net, cell);
ec26815ad   David Howells   [AFS]: Clean up t...
120
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
  		goto inval;
  	}
5b86d4ff5   David Howells   afs: Implement ne...
123
  	ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124

ec26815ad   David Howells   [AFS]: Clean up t...
125
  done:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
  	_leave(" = %d", ret);
  	return ret;
ec26815ad   David Howells   [AFS]: Clean up t...
128
  inval:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
131
132
  	ret = -EINVAL;
  	printk("kAFS: Invalid Command on /proc/fs/afs/cells file
  ");
  	goto done;
ec26815ad   David Howells   [AFS]: Clean up t...
133
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134

5d9de25d9   David Howells   afs: Rearrange fs...
135
  /*
5b86d4ff5   David Howells   afs: Implement ne...
136
   * Display the name of the current workstation cell.
5d9de25d9   David Howells   afs: Rearrange fs...
137
   */
5b86d4ff5   David Howells   afs: Implement ne...
138
  static int afs_proc_rootcell_show(struct seq_file *m, void *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  {
37ab63688   David Howells   afs: Implement @c...
140
  	struct afs_cell *cell;
5b86d4ff5   David Howells   afs: Implement ne...
141
142
143
144
145
146
147
148
149
150
151
152
  	struct afs_net *net;
  
  	net = afs_seq2net_single(m);
  	if (rcu_access_pointer(net->ws_cell)) {
  		rcu_read_lock();
  		cell = rcu_dereference(net->ws_cell);
  		if (cell)
  			seq_printf(m, "%s
  ", cell->name);
  		rcu_read_unlock();
  	}
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  /*
5d9de25d9   David Howells   afs: Rearrange fs...
155
156
157
158
   * Set the current workstation cell and optionally supply its list of volume
   * location servers.
   *
   *	echo "cell.name:192.168.231.14" >/proc/fs/afs/rootcell
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
   */
5b86d4ff5   David Howells   afs: Implement ne...
160
  static int afs_proc_rootcell_write(struct file *file, char *buf, size_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  {
5b86d4ff5   David Howells   afs: Implement ne...
162
163
164
  	struct seq_file *m = file->private_data;
  	struct afs_net *net = afs_seq2net_single(m);
  	char *s;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  	int ret;
6f8880d8e   David Howells   afs: Implement @s...
166
  	ret = -EINVAL;
5b86d4ff5   David Howells   afs: Implement ne...
167
  	if (buf[0] == '.')
6f8880d8e   David Howells   afs: Implement @s...
168
  		goto out;
5b86d4ff5   David Howells   afs: Implement ne...
169
  	if (memchr(buf, '/', size))
6f8880d8e   David Howells   afs: Implement @s...
170
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  	/* trim to first NL */
5b86d4ff5   David Howells   afs: Implement ne...
172
173
  	s = memchr(buf, '
  ', size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
177
  	if (s)
  		*s = 0;
  
  	/* determine command to perform */
5b86d4ff5   David Howells   afs: Implement ne...
178
  	_debug("rootcell=%s", buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179

5b86d4ff5   David Howells   afs: Implement ne...
180
  	ret = afs_cell_init(net, buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181

6f8880d8e   David Howells   afs: Implement @s...
182
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
  	_leave(" = %d", ret);
  	return ret;
ec26815ad   David Howells   [AFS]: Clean up t...
185
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186

f06916895   David Howells   afs: Rearrange fs...
187
188
189
190
191
192
193
  static const char afs_vol_types[3][3] = {
  	[AFSVL_RWVOL]	= "RW",
  	[AFSVL_ROVOL]	= "RO",
  	[AFSVL_BACKVOL]	= "BK",
  };
  
  /*
5d9de25d9   David Howells   afs: Rearrange fs...
194
   * Display the list of volumes known to a cell.
f06916895   David Howells   afs: Rearrange fs...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
   */
  static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
  {
  	struct afs_cell *cell = PDE_DATA(file_inode(m->file));
  	struct afs_volume *vol = list_entry(v, struct afs_volume, proc_link);
  
  	/* Display header on line 1 */
  	if (v == &cell->proc_volumes) {
  		seq_puts(m, "USE VID      TY
  ");
  		return 0;
  	}
  
  	seq_printf(m, "%3d %08x %s
  ",
  		   atomic_read(&vol->usage), vol->vid,
  		   afs_vol_types[vol->type]);
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
fe342cf77   David Howells   afs: Fix checker ...
216
  	__acquires(cell->proc_lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  {
353861cf0   Christoph Hellwig   afs: simplify pro...
218
  	struct afs_cell *cell = PDE_DATA(file_inode(m->file));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219

d2ddc776a   David Howells   afs: Overhaul vol...
220
221
  	read_lock(&cell->proc_lock);
  	return seq_list_start_head(&cell->proc_volumes, *_pos);
ec26815ad   David Howells   [AFS]: Clean up t...
222
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223

5b86d4ff5   David Howells   afs: Implement ne...
224
  static void *afs_proc_cell_volumes_next(struct seq_file *m, void *v,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
  					loff_t *_pos)
  {
5b86d4ff5   David Howells   afs: Implement ne...
227
  	struct afs_cell *cell = PDE_DATA(file_inode(m->file));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228

d2ddc776a   David Howells   afs: Overhaul vol...
229
  	return seq_list_next(v, &cell->proc_volumes, _pos);
ec26815ad   David Howells   [AFS]: Clean up t...
230
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231

5b86d4ff5   David Howells   afs: Implement ne...
232
  static void afs_proc_cell_volumes_stop(struct seq_file *m, void *v)
fe342cf77   David Howells   afs: Fix checker ...
233
  	__releases(cell->proc_lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
  {
5b86d4ff5   David Howells   afs: Implement ne...
235
  	struct afs_cell *cell = PDE_DATA(file_inode(m->file));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236

d2ddc776a   David Howells   afs: Overhaul vol...
237
  	read_unlock(&cell->proc_lock);
ec26815ad   David Howells   [AFS]: Clean up t...
238
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239

5d9de25d9   David Howells   afs: Rearrange fs...
240
241
242
243
244
245
  static const struct seq_operations afs_proc_cell_volumes_ops = {
  	.start	= afs_proc_cell_volumes_start,
  	.next	= afs_proc_cell_volumes_next,
  	.stop	= afs_proc_cell_volumes_stop,
  	.show	= afs_proc_cell_volumes_show,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  /*
5d9de25d9   David Howells   afs: Rearrange fs...
247
   * Display the list of Volume Location servers we're using for a cell.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
   */
f06916895   David Howells   afs: Rearrange fs...
249
  static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
  {
f06916895   David Howells   afs: Rearrange fs...
251
  	struct sockaddr_rxrpc *addr = v;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252

f06916895   David Howells   afs: Rearrange fs...
253
254
255
256
  	/* display header on line 1 */
  	if (v == (void *)1) {
  		seq_puts(m, "ADDRESS
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
  		return 0;
  	}
f06916895   David Howells   afs: Rearrange fs...
259
260
261
  	/* display one cell per line on subsequent lines */
  	seq_printf(m, "%pISp
  ", &addr->transport);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
  	return 0;
ec26815ad   David Howells   [AFS]: Clean up t...
263
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
  static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
fe342cf77   David Howells   afs: Fix checker ...
266
  	__acquires(rcu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
  {
8b2a464ce   David Howells   afs: Add an addre...
268
  	struct afs_addr_list *alist;
353861cf0   Christoph Hellwig   afs: simplify pro...
269
  	struct afs_cell *cell = PDE_DATA(file_inode(m->file));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
  	loff_t pos = *_pos;
8b2a464ce   David Howells   afs: Add an addre...
271
  	rcu_read_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272

8b2a464ce   David Howells   afs: Add an addre...
273
  	alist = rcu_dereference(cell->vl_addrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
276
277
278
  
  	/* allow for the header line */
  	if (!pos)
  		return (void *) 1;
  	pos--;
8b2a464ce   David Howells   afs: Add an addre...
279
  	if (!alist || pos >= alist->nr_addrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
  		return NULL;
8b2a464ce   David Howells   afs: Add an addre...
281
  	return alist->addrs + pos;
ec26815ad   David Howells   [AFS]: Clean up t...
282
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283

5b86d4ff5   David Howells   afs: Implement ne...
284
  static void *afs_proc_cell_vlservers_next(struct seq_file *m, void *v,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
  					  loff_t *_pos)
  {
8b2a464ce   David Howells   afs: Add an addre...
287
  	struct afs_addr_list *alist;
5b86d4ff5   David Howells   afs: Implement ne...
288
  	struct afs_cell *cell = PDE_DATA(file_inode(m->file));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
  	loff_t pos;
8b2a464ce   David Howells   afs: Add an addre...
290
  	alist = rcu_dereference(cell->vl_addrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
  
  	pos = *_pos;
  	(*_pos)++;
8b2a464ce   David Howells   afs: Add an addre...
294
  	if (!alist || pos >= alist->nr_addrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  		return NULL;
8b2a464ce   David Howells   afs: Add an addre...
296
  	return alist->addrs + pos;
ec26815ad   David Howells   [AFS]: Clean up t...
297
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298

5b86d4ff5   David Howells   afs: Implement ne...
299
  static void afs_proc_cell_vlservers_stop(struct seq_file *m, void *v)
fe342cf77   David Howells   afs: Fix checker ...
300
  	__releases(rcu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
  {
8b2a464ce   David Howells   afs: Add an addre...
302
  	rcu_read_unlock();
ec26815ad   David Howells   [AFS]: Clean up t...
303
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304

5d9de25d9   David Howells   afs: Rearrange fs...
305
306
307
308
309
310
  static const struct seq_operations afs_proc_cell_vlservers_ops = {
  	.start	= afs_proc_cell_vlservers_start,
  	.next	= afs_proc_cell_vlservers_next,
  	.stop	= afs_proc_cell_vlservers_stop,
  	.show	= afs_proc_cell_vlservers_show,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
  /*
5d9de25d9   David Howells   afs: Rearrange fs...
312
   * Display the list of fileservers we're using within a namespace.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
   */
f06916895   David Howells   afs: Rearrange fs...
314
  static int afs_proc_servers_show(struct seq_file *m, void *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
  {
f06916895   David Howells   afs: Rearrange fs...
316
317
  	struct afs_server *server;
  	struct afs_addr_list *alist;
0aac4bce4   David Howells   afs: Show all of ...
318
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319

f06916895   David Howells   afs: Rearrange fs...
320
321
322
  	if (v == SEQ_START_TOKEN) {
  		seq_puts(m, "UUID                                 USE ADDR
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
  		return 0;
  	}
f06916895   David Howells   afs: Rearrange fs...
325
326
  	server = list_entry(v, struct afs_server, proc_link);
  	alist = rcu_dereference(server->addresses);
0aac4bce4   David Howells   afs: Show all of ...
327
328
  	seq_printf(m, "%pU %3d %pISpc%s
  ",
f06916895   David Howells   afs: Rearrange fs...
329
330
  		   &server->uuid,
  		   atomic_read(&server->usage),
0aac4bce4   David Howells   afs: Show all of ...
331
332
333
334
335
336
337
  		   &alist->addrs[0].transport,
  		   alist->index == 0 ? "*" : "");
  	for (i = 1; i < alist->nr_addrs; i++)
  		seq_printf(m, "                                         %pISpc%s
  ",
  			   &alist->addrs[i].transport,
  			   alist->index == i ? "*" : "");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
  	return 0;
ec26815ad   David Howells   [AFS]: Clean up t...
339
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340

d2ddc776a   David Howells   afs: Overhaul vol...
341
  static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos)
fe342cf77   David Howells   afs: Fix checker ...
342
  	__acquires(rcu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
  {
d2ddc776a   David Howells   afs: Overhaul vol...
344
  	rcu_read_lock();
5d9de25d9   David Howells   afs: Rearrange fs...
345
  	return seq_hlist_start_head_rcu(&afs_seq2net(m)->fs_proc, *_pos);
ec26815ad   David Howells   [AFS]: Clean up t...
346
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347

d2ddc776a   David Howells   afs: Overhaul vol...
348
  static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
  {
5d9de25d9   David Howells   afs: Rearrange fs...
350
  	return seq_hlist_next_rcu(v, &afs_seq2net(m)->fs_proc, _pos);
ec26815ad   David Howells   [AFS]: Clean up t...
351
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352

5b86d4ff5   David Howells   afs: Implement ne...
353
  static void afs_proc_servers_stop(struct seq_file *m, void *v)
fe342cf77   David Howells   afs: Fix checker ...
354
  	__releases(rcu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
  {
d2ddc776a   David Howells   afs: Overhaul vol...
356
  	rcu_read_unlock();
ec26815ad   David Howells   [AFS]: Clean up t...
357
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358

5d9de25d9   David Howells   afs: Rearrange fs...
359
360
361
362
363
364
  static const struct seq_operations afs_proc_servers_ops = {
  	.start	= afs_proc_servers_start,
  	.next	= afs_proc_servers_next,
  	.stop	= afs_proc_servers_stop,
  	.show	= afs_proc_servers_show,
  };
6f8880d8e   David Howells   afs: Implement @s...
365

6f8880d8e   David Howells   afs: Implement @s...
366
  /*
5d9de25d9   David Howells   afs: Rearrange fs...
367
368
   * Display the list of strings that may be substituted for the @sys pathname
   * macro.
6f8880d8e   David Howells   afs: Implement @s...
369
   */
5d9de25d9   David Howells   afs: Rearrange fs...
370
  static int afs_proc_sysname_show(struct seq_file *m, void *v)
6f8880d8e   David Howells   afs: Implement @s...
371
  {
5d9de25d9   David Howells   afs: Rearrange fs...
372
373
374
  	struct afs_net *net = afs_seq2net(m);
  	struct afs_sysnames *sysnames = net->sysnames;
  	unsigned int i = (unsigned long)v - 1;
6f8880d8e   David Howells   afs: Implement @s...
375

5d9de25d9   David Howells   afs: Rearrange fs...
376
377
378
379
380
  	if (i < sysnames->nr)
  		seq_printf(m, "%s
  ", sysnames->subs[i]);
  	return 0;
  }
6f8880d8e   David Howells   afs: Implement @s...
381

5d9de25d9   David Howells   afs: Rearrange fs...
382
383
384
385
  static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos)
  	__acquires(&net->sysnames_lock)
  {
  	struct afs_net *net = afs_seq2net(m);
5b86d4ff5   David Howells   afs: Implement ne...
386
  	struct afs_sysnames *names;
6f8880d8e   David Howells   afs: Implement @s...
387

5d9de25d9   David Howells   afs: Rearrange fs...
388
  	read_lock(&net->sysnames_lock);
6f8880d8e   David Howells   afs: Implement @s...
389

5b86d4ff5   David Howells   afs: Implement ne...
390
  	names = net->sysnames;
5d9de25d9   David Howells   afs: Rearrange fs...
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
  	if (*pos >= names->nr)
  		return NULL;
  	return (void *)(unsigned long)(*pos + 1);
  }
  
  static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos)
  {
  	struct afs_net *net = afs_seq2net(m);
  	struct afs_sysnames *names = net->sysnames;
  
  	*pos += 1;
  	if (*pos >= names->nr)
  		return NULL;
  	return (void *)(unsigned long)(*pos + 1);
  }
  
  static void afs_proc_sysname_stop(struct seq_file *m, void *v)
  	__releases(&net->sysnames_lock)
  {
  	struct afs_net *net = afs_seq2net(m);
  
  	read_unlock(&net->sysnames_lock);
6f8880d8e   David Howells   afs: Implement @s...
413
  }
5d9de25d9   David Howells   afs: Rearrange fs...
414
415
416
417
418
419
  static const struct seq_operations afs_proc_sysname_ops = {
  	.start	= afs_proc_sysname_start,
  	.next	= afs_proc_sysname_next,
  	.stop	= afs_proc_sysname_stop,
  	.show	= afs_proc_sysname_show,
  };
6f8880d8e   David Howells   afs: Implement @s...
420
  /*
5d9de25d9   David Howells   afs: Rearrange fs...
421
   * Allow the @sys substitution to be configured.
6f8880d8e   David Howells   afs: Implement @s...
422
   */
5b86d4ff5   David Howells   afs: Implement ne...
423
  static int afs_proc_sysname_write(struct file *file, char *buf, size_t size)
6f8880d8e   David Howells   afs: Implement @s...
424
  {
5b86d4ff5   David Howells   afs: Implement ne...
425
  	struct afs_sysnames *sysnames, *kill;
6f8880d8e   David Howells   afs: Implement @s...
426
  	struct seq_file *m = file->private_data;
5b86d4ff5   David Howells   afs: Implement ne...
427
428
  	struct afs_net *net = afs_seq2net(m);
  	char *s, *p, *sub;
6f8880d8e   David Howells   afs: Implement @s...
429
  	int ret, len;
5b86d4ff5   David Howells   afs: Implement ne...
430
  	sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
6f8880d8e   David Howells   afs: Implement @s...
431
  	if (!sysnames)
5b86d4ff5   David Howells   afs: Implement ne...
432
433
434
  		return -ENOMEM;
  	refcount_set(&sysnames->usage, 1);
  	kill = sysnames;
6f8880d8e   David Howells   afs: Implement @s...
435

5b86d4ff5   David Howells   afs: Implement ne...
436
  	p = buf;
6f8880d8e   David Howells   afs: Implement @s...
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
  	while ((s = strsep(&p, " \t
  "))) {
  		len = strlen(s);
  		if (len == 0)
  			continue;
  		ret = -ENAMETOOLONG;
  		if (len >= AFSNAMEMAX)
  			goto error;
  
  		if (len >= 4 &&
  		    s[len - 4] == '@' &&
  		    s[len - 3] == 's' &&
  		    s[len - 2] == 'y' &&
  		    s[len - 1] == 's')
  			/* Protect against recursion */
  			goto invalid;
  
  		if (s[0] == '.' &&
  		    (len < 2 || (len == 2 && s[1] == '.')))
  			goto invalid;
  
  		if (memchr(s, '/', len))
  			goto invalid;
  
  		ret = -EFBIG;
  		if (sysnames->nr >= AFS_NR_SYSNAME)
  			goto out;
  
  		if (strcmp(s, afs_init_sysname) == 0) {
  			sub = (char *)afs_init_sysname;
  		} else {
  			ret = -ENOMEM;
  			sub = kmemdup(s, len + 1, GFP_KERNEL);
  			if (!sub)
  				goto out;
  		}
  
  		sysnames->subs[sysnames->nr] = sub;
  		sysnames->nr++;
  	}
5b86d4ff5   David Howells   afs: Implement ne...
477
478
479
480
481
482
483
484
485
486
  	if (sysnames->nr == 0) {
  		sysnames->subs[0] = sysnames->blank;
  		sysnames->nr++;
  	}
  
  	write_lock(&net->sysnames_lock);
  	kill = net->sysnames;
  	net->sysnames = sysnames;
  	write_unlock(&net->sysnames_lock);
  	ret = 0;
6f8880d8e   David Howells   afs: Implement @s...
487
  out:
5b86d4ff5   David Howells   afs: Implement ne...
488
  	afs_put_sysnames(kill);
6f8880d8e   David Howells   afs: Implement @s...
489
490
491
492
493
  	return ret;
  
  invalid:
  	ret = -EINVAL;
  error:
6f8880d8e   David Howells   afs: Implement @s...
494
495
  	goto out;
  }
5d9de25d9   David Howells   afs: Rearrange fs...
496
497
498
499
500
501
502
503
504
505
506
  void afs_put_sysnames(struct afs_sysnames *sysnames)
  {
  	int i;
  
  	if (sysnames && refcount_dec_and_test(&sysnames->usage)) {
  		for (i = 0; i < sysnames->nr; i++)
  			if (sysnames->subs[i] != afs_init_sysname &&
  			    sysnames->subs[i] != sysnames->blank)
  				kfree(sysnames->subs[i]);
  	}
  }
d55b4da43   David Howells   afs: Introduce a ...
507
508
509
510
511
  /*
   * Display general per-net namespace statistics
   */
  static int afs_proc_stats_show(struct seq_file *m, void *v)
  {
5b86d4ff5   David Howells   afs: Implement ne...
512
  	struct afs_net *net = afs_seq2net_single(m);
d55b4da43   David Howells   afs: Introduce a ...
513
514
515
  
  	seq_puts(m, "kAFS statistics
  ");
f3ddee8dc   David Howells   afs: Fix director...
516
517
  	seq_printf(m, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u
  ",
d55b4da43   David Howells   afs: Introduce a ...
518
519
  		   atomic_read(&net->n_lookup),
  		   atomic_read(&net->n_reval),
f3ddee8dc   David Howells   afs: Fix director...
520
521
  		   atomic_read(&net->n_inval),
  		   atomic_read(&net->n_relpg));
d55b4da43   David Howells   afs: Introduce a ...
522
523
524
525
  
  	seq_printf(m, "dir-data: rdpg=%u
  ",
  		   atomic_read(&net->n_read_dir));
63a4681ff   David Howells   afs: Locally edit...
526
527
528
529
530
  
  	seq_printf(m, "dir-edit: cr=%u rm=%u
  ",
  		   atomic_read(&net->n_dir_cr),
  		   atomic_read(&net->n_dir_rm));
76a5cb6fc   David Howells   afs: Add stats fo...
531
532
533
534
535
536
537
538
539
  
  	seq_printf(m, "file-rd : n=%u nb=%lu
  ",
  		   atomic_read(&net->n_fetches),
  		   atomic_long_read(&net->n_fetch_bytes));
  	seq_printf(m, "file-wr : n=%u nb=%lu
  ",
  		   atomic_read(&net->n_stores),
  		   atomic_long_read(&net->n_store_bytes));
d55b4da43   David Howells   afs: Introduce a ...
540
541
  	return 0;
  }
10495a007   David Howells   afs: Move /proc m...
542
543
544
545
  
  /*
   * initialise /proc/fs/afs/<cell>/
   */
5b86d4ff5   David Howells   afs: Implement ne...
546
  int afs_proc_cell_setup(struct afs_cell *cell)
10495a007   David Howells   afs: Move /proc m...
547
548
  {
  	struct proc_dir_entry *dir;
5b86d4ff5   David Howells   afs: Implement ne...
549
  	struct afs_net *net = cell->net;
10495a007   David Howells   afs: Move /proc m...
550
551
  
  	_enter("%p{%s},%p", cell, cell->name, net->proc_afs);
5b86d4ff5   David Howells   afs: Implement ne...
552
  	dir = proc_net_mkdir(net->net, cell->name, net->proc_afs);
10495a007   David Howells   afs: Move /proc m...
553
554
  	if (!dir)
  		goto error_dir;
5b86d4ff5   David Howells   afs: Implement ne...
555
556
557
558
559
560
561
562
  	if (!proc_create_net_data("vlservers", 0444, dir,
  				  &afs_proc_cell_vlservers_ops,
  				  sizeof(struct seq_net_private),
  				  cell) ||
  	    !proc_create_net_data("volumes", 0444, dir,
  				  &afs_proc_cell_volumes_ops,
  				  sizeof(struct seq_net_private),
  				  cell))
10495a007   David Howells   afs: Move /proc m...
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
  		goto error_tree;
  
  	_leave(" = 0");
  	return 0;
  
  error_tree:
  	remove_proc_subtree(cell->name, net->proc_afs);
  error_dir:
  	_leave(" = -ENOMEM");
  	return -ENOMEM;
  }
  
  /*
   * remove /proc/fs/afs/<cell>/
   */
5b86d4ff5   David Howells   afs: Implement ne...
578
  void afs_proc_cell_remove(struct afs_cell *cell)
10495a007   David Howells   afs: Move /proc m...
579
  {
5b86d4ff5   David Howells   afs: Implement ne...
580
  	struct afs_net *net = cell->net;
10495a007   David Howells   afs: Move /proc m...
581

5b86d4ff5   David Howells   afs: Implement ne...
582
  	_enter("");
10495a007   David Howells   afs: Move /proc m...
583
  	remove_proc_subtree(cell->name, net->proc_afs);
10495a007   David Howells   afs: Move /proc m...
584
585
586
587
588
589
590
591
  	_leave("");
  }
  
  /*
   * initialise the /proc/fs/afs/ directory
   */
  int afs_proc_init(struct afs_net *net)
  {
5b86d4ff5   David Howells   afs: Implement ne...
592
  	struct proc_dir_entry *p;
10495a007   David Howells   afs: Move /proc m...
593
  	_enter("");
5b86d4ff5   David Howells   afs: Implement ne...
594
595
  	p = proc_net_mkdir(net->net, "afs", net->net->proc_net);
  	if (!p)
10495a007   David Howells   afs: Move /proc m...
596
  		goto error_dir;
5b86d4ff5   David Howells   afs: Implement ne...
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
  	if (!proc_create_net_data_write("cells", 0644, p,
  					&afs_proc_cells_ops,
  					afs_proc_cells_write,
  					sizeof(struct seq_net_private),
  					NULL) ||
  	    !proc_create_net_single_write("rootcell", 0644, p,
  					  afs_proc_rootcell_show,
  					  afs_proc_rootcell_write,
  					  NULL) ||
  	    !proc_create_net("servers", 0444, p, &afs_proc_servers_ops,
  			     sizeof(struct seq_net_private)) ||
  	    !proc_create_net_single("stats", 0444, p, afs_proc_stats_show, NULL) ||
  	    !proc_create_net_data_write("sysname", 0644, p,
  					&afs_proc_sysname_ops,
  					afs_proc_sysname_write,
  					sizeof(struct seq_net_private),
  					NULL))
10495a007   David Howells   afs: Move /proc m...
614
  		goto error_tree;
5b86d4ff5   David Howells   afs: Implement ne...
615
  	net->proc_afs = p;
10495a007   David Howells   afs: Move /proc m...
616
617
618
619
  	_leave(" = 0");
  	return 0;
  
  error_tree:
5b86d4ff5   David Howells   afs: Implement ne...
620
  	proc_remove(p);
10495a007   David Howells   afs: Move /proc m...
621
622
623
624
625
626
627
628
629
630
631
632
633
  error_dir:
  	_leave(" = -ENOMEM");
  	return -ENOMEM;
  }
  
  /*
   * clean up the /proc/fs/afs/ directory
   */
  void afs_proc_cleanup(struct afs_net *net)
  {
  	proc_remove(net->proc_afs);
  	net->proc_afs = NULL;
  }