blob: 9cf9ce88a8dd349ea70e2155e2b3a4ba31e78233 [file] [log] [blame]
David Howellsec268152007-04-26 15:49:28 -07001/* /proc interface for AFS
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/slab.h>
13#include <linux/module.h>
14#include <linux/proc_fs.h>
15#include <linux/seq_file.h>
Alexey Dobriyane8edc6e2007-05-21 01:22:52 +040016#include <linux/sched.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080017#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include "internal.h"
19
David Howellsf044c882017-11-02 15:27:45 +000020static inline struct afs_net *afs_proc2net(struct file *f)
21{
22 return &__afs_net;
23}
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
David Howellsf044c882017-11-02 15:27:45 +000025static inline struct afs_net *afs_seq2net(struct seq_file *m)
26{
27 return &__afs_net; // TODO: use seq_file_net(m)
28}
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30static int afs_proc_cells_open(struct inode *inode, struct file *file);
31static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos);
32static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos);
33static void afs_proc_cells_stop(struct seq_file *p, void *v);
34static int afs_proc_cells_show(struct seq_file *m, void *v);
35static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
36 size_t size, loff_t *_pos);
37
James Morris88e9d342009-09-22 16:43:43 -070038static const struct seq_operations afs_proc_cells_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070039 .start = afs_proc_cells_start,
40 .next = afs_proc_cells_next,
41 .stop = afs_proc_cells_stop,
42 .show = afs_proc_cells_show,
43};
44
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -080045static const struct file_operations afs_proc_cells_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 .open = afs_proc_cells_open,
47 .read = seq_read,
48 .write = afs_proc_cells_write,
49 .llseek = seq_lseek,
50 .release = seq_release,
51};
52
Linus Torvalds1da177e2005-04-16 15:20:36 -070053static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
54 size_t size, loff_t *_pos);
55static ssize_t afs_proc_rootcell_write(struct file *file,
56 const char __user *buf,
57 size_t size, loff_t *_pos);
58
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -080059static const struct file_operations afs_proc_rootcell_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 .read = afs_proc_rootcell_read,
61 .write = afs_proc_rootcell_write,
62 .llseek = no_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -070063};
64
65static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file);
Linus Torvalds1da177e2005-04-16 15:20:36 -070066static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos);
67static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
68 loff_t *pos);
69static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v);
70static int afs_proc_cell_volumes_show(struct seq_file *m, void *v);
71
James Morris88e9d342009-09-22 16:43:43 -070072static const struct seq_operations afs_proc_cell_volumes_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 .start = afs_proc_cell_volumes_start,
74 .next = afs_proc_cell_volumes_next,
75 .stop = afs_proc_cell_volumes_stop,
76 .show = afs_proc_cell_volumes_show,
77};
78
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -080079static const struct file_operations afs_proc_cell_volumes_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 .open = afs_proc_cell_volumes_open,
81 .read = seq_read,
82 .llseek = seq_lseek,
Al Virob42d5702013-11-22 01:53:47 -050083 .release = seq_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -070084};
85
86static int afs_proc_cell_vlservers_open(struct inode *inode,
87 struct file *file);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos);
89static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
90 loff_t *pos);
91static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v);
92static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v);
93
James Morris88e9d342009-09-22 16:43:43 -070094static const struct seq_operations afs_proc_cell_vlservers_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 .start = afs_proc_cell_vlservers_start,
96 .next = afs_proc_cell_vlservers_next,
97 .stop = afs_proc_cell_vlservers_stop,
98 .show = afs_proc_cell_vlservers_show,
99};
100
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800101static const struct file_operations afs_proc_cell_vlservers_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 .open = afs_proc_cell_vlservers_open,
103 .read = seq_read,
104 .llseek = seq_lseek,
Al Virob42d5702013-11-22 01:53:47 -0500105 .release = seq_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106};
107
108static int afs_proc_cell_servers_open(struct inode *inode, struct file *file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109static void *afs_proc_cell_servers_start(struct seq_file *p, loff_t *pos);
110static void *afs_proc_cell_servers_next(struct seq_file *p, void *v,
111 loff_t *pos);
112static void afs_proc_cell_servers_stop(struct seq_file *p, void *v);
113static int afs_proc_cell_servers_show(struct seq_file *m, void *v);
114
James Morris88e9d342009-09-22 16:43:43 -0700115static const struct seq_operations afs_proc_cell_servers_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 .start = afs_proc_cell_servers_start,
117 .next = afs_proc_cell_servers_next,
118 .stop = afs_proc_cell_servers_stop,
119 .show = afs_proc_cell_servers_show,
120};
121
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800122static const struct file_operations afs_proc_cell_servers_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 .open = afs_proc_cell_servers_open,
124 .read = seq_read,
125 .llseek = seq_lseek,
Al Virob42d5702013-11-22 01:53:47 -0500126 .release = seq_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127};
128
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129/*
130 * initialise the /proc/fs/afs/ directory
131 */
David Howellsf044c882017-11-02 15:27:45 +0000132int afs_proc_init(struct afs_net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 _enter("");
135
David Howellsf044c882017-11-02 15:27:45 +0000136 net->proc_afs = proc_mkdir("fs/afs", NULL);
137 if (!net->proc_afs)
David Howellsec268152007-04-26 15:49:28 -0700138 goto error_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
David Howellsf044c882017-11-02 15:27:45 +0000140 if (!proc_create("cells", 0644, net->proc_afs, &afs_proc_cells_fops) ||
141 !proc_create("rootcell", 0644, net->proc_afs, &afs_proc_rootcell_fops))
Al Virob42d5702013-11-22 01:53:47 -0500142 goto error_tree;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144 _leave(" = 0");
145 return 0;
146
Al Virob42d5702013-11-22 01:53:47 -0500147error_tree:
David Howellsf044c882017-11-02 15:27:45 +0000148 proc_remove(net->proc_afs);
David Howellsec268152007-04-26 15:49:28 -0700149error_dir:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 _leave(" = -ENOMEM");
151 return -ENOMEM;
David Howellsec268152007-04-26 15:49:28 -0700152}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154/*
155 * clean up the /proc/fs/afs/ directory
156 */
David Howellsf044c882017-11-02 15:27:45 +0000157void afs_proc_cleanup(struct afs_net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158{
David Howellsf044c882017-11-02 15:27:45 +0000159 proc_remove(net->proc_afs);
160 net->proc_afs = NULL;
David Howellsec268152007-04-26 15:49:28 -0700161}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163/*
164 * open "/proc/fs/afs/cells" which provides a summary of extant cells
165 */
166static int afs_proc_cells_open(struct inode *inode, struct file *file)
167{
168 struct seq_file *m;
169 int ret;
170
171 ret = seq_open(file, &afs_proc_cells_ops);
172 if (ret < 0)
173 return ret;
174
175 m = file->private_data;
Al Virod9dda782013-03-31 18:16:14 -0400176 m->private = PDE_DATA(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
178 return 0;
David Howellsec268152007-04-26 15:49:28 -0700179}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181/*
182 * set up the iterator to start reading from the cells list and return the
183 * first item
184 */
185static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
186{
David Howellsf044c882017-11-02 15:27:45 +0000187 struct afs_net *net = afs_seq2net(m);
188
David Howells989782d2017-11-02 15:27:50 +0000189 rcu_read_lock();
David Howellsf044c882017-11-02 15:27:45 +0000190 return seq_list_start_head(&net->proc_cells, *_pos);
David Howellsec268152007-04-26 15:49:28 -0700191}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193/*
194 * move to next cell in cells list
195 */
David Howellsf044c882017-11-02 15:27:45 +0000196static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197{
David Howellsf044c882017-11-02 15:27:45 +0000198 struct afs_net *net = afs_seq2net(m);
199
200 return seq_list_next(v, &net->proc_cells, pos);
David Howellsec268152007-04-26 15:49:28 -0700201}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203/*
204 * clean up after reading from the cells list
205 */
David Howellsf044c882017-11-02 15:27:45 +0000206static void afs_proc_cells_stop(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207{
David Howells989782d2017-11-02 15:27:50 +0000208 rcu_read_unlock();
David Howellsec268152007-04-26 15:49:28 -0700209}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211/*
212 * display a header line followed by a load of cell lines
213 */
214static int afs_proc_cells_show(struct seq_file *m, void *v)
215{
216 struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
David Howellsf044c882017-11-02 15:27:45 +0000217 struct afs_net *net = afs_seq2net(m);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
David Howellsf044c882017-11-02 15:27:45 +0000219 if (v == &net->proc_cells) {
David Howellsec268152007-04-26 15:49:28 -0700220 /* display header on line 1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 seq_puts(m, "USE NAME\n");
222 return 0;
223 }
224
225 /* display one cell per line on subsequent lines */
David Howells989782d2017-11-02 15:27:50 +0000226 seq_printf(m, "%3u %s\n", atomic_read(&cell->usage), cell->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 return 0;
David Howellsec268152007-04-26 15:49:28 -0700228}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230/*
231 * handle writes to /proc/fs/afs/cells
232 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
233 */
234static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
235 size_t size, loff_t *_pos)
236{
David Howellsf044c882017-11-02 15:27:45 +0000237 struct afs_net *net = afs_proc2net(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 char *kbuf, *name, *args;
239 int ret;
240
241 /* start by dragging the command into memory */
242 if (size <= 1 || size >= PAGE_SIZE)
243 return -EINVAL;
244
Al Viro16e5c1f2015-12-24 00:06:05 -0500245 kbuf = memdup_user_nul(buf, size);
246 if (IS_ERR(kbuf))
247 return PTR_ERR(kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
249 /* trim to first NL */
250 name = memchr(kbuf, '\n', size);
251 if (name)
252 *name = 0;
253
254 /* split into command, name and argslist */
255 name = strchr(kbuf, ' ');
256 if (!name)
257 goto inval;
258 do {
259 *name++ = 0;
260 } while(*name == ' ');
261 if (!*name)
262 goto inval;
263
264 args = strchr(name, ' ');
265 if (!args)
266 goto inval;
267 do {
268 *args++ = 0;
269 } while(*args == ' ');
270 if (!*args)
271 goto inval;
272
273 /* determine command to perform */
274 _debug("cmd=%s name=%s args=%s", kbuf, name, args);
275
276 if (strcmp(kbuf, "add") == 0) {
277 struct afs_cell *cell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
David Howells989782d2017-11-02 15:27:50 +0000279 cell = afs_lookup_cell(net, name, strlen(name), args, true);
David Howells08e0e7c2007-04-26 15:55:03 -0700280 if (IS_ERR(cell)) {
281 ret = PTR_ERR(cell);
282 goto done;
283 }
284
David Howells989782d2017-11-02 15:27:50 +0000285 set_bit(AFS_CELL_FL_NO_GC, &cell->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 printk("kAFS: Added new cell '%s'\n", name);
David Howellsec268152007-04-26 15:49:28 -0700287 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 goto inval;
289 }
290
291 ret = size;
292
David Howellsec268152007-04-26 15:49:28 -0700293done:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 kfree(kbuf);
295 _leave(" = %d", ret);
296 return ret;
297
David Howellsec268152007-04-26 15:49:28 -0700298inval:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 ret = -EINVAL;
300 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
301 goto done;
David Howellsec268152007-04-26 15:49:28 -0700302}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
305 size_t size, loff_t *_pos)
306{
307 return 0;
308}
309
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310/*
311 * handle writes to /proc/fs/afs/rootcell
312 * - to initialize rootcell: echo "cell.name:192.168.231.14"
313 */
314static ssize_t afs_proc_rootcell_write(struct file *file,
315 const char __user *buf,
316 size_t size, loff_t *_pos)
317{
David Howellsf044c882017-11-02 15:27:45 +0000318 struct afs_net *net = afs_proc2net(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 char *kbuf, *s;
320 int ret;
321
322 /* start by dragging the command into memory */
323 if (size <= 1 || size >= PAGE_SIZE)
324 return -EINVAL;
325
Al Viro16e5c1f2015-12-24 00:06:05 -0500326 kbuf = memdup_user_nul(buf, size);
327 if (IS_ERR(kbuf))
328 return PTR_ERR(kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 /* trim to first NL */
331 s = memchr(kbuf, '\n', size);
332 if (s)
333 *s = 0;
334
335 /* determine command to perform */
336 _debug("rootcell=%s", kbuf);
337
David Howellsf044c882017-11-02 15:27:45 +0000338 ret = afs_cell_init(net, kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 if (ret >= 0)
340 ret = size; /* consume everything, always */
341
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 kfree(kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 _leave(" = %d", ret);
344 return ret;
David Howellsec268152007-04-26 15:49:28 -0700345}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347/*
348 * initialise /proc/fs/afs/<cell>/
349 */
David Howellsf044c882017-11-02 15:27:45 +0000350int afs_proc_cell_setup(struct afs_net *net, struct afs_cell *cell)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351{
Al Virob42d5702013-11-22 01:53:47 -0500352 struct proc_dir_entry *dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
David Howells989782d2017-11-02 15:27:50 +0000354 _enter("%p{%s},%p", cell, cell->name, net->proc_afs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
David Howellsf044c882017-11-02 15:27:45 +0000356 dir = proc_mkdir(cell->name, net->proc_afs);
Al Virob42d5702013-11-22 01:53:47 -0500357 if (!dir)
David Howellsec268152007-04-26 15:49:28 -0700358 goto error_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Al Virob42d5702013-11-22 01:53:47 -0500360 if (!proc_create_data("servers", 0, dir,
361 &afs_proc_cell_servers_fops, cell) ||
362 !proc_create_data("vlservers", 0, dir,
363 &afs_proc_cell_vlservers_fops, cell) ||
364 !proc_create_data("volumes", 0, dir,
365 &afs_proc_cell_volumes_fops, cell))
366 goto error_tree;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
368 _leave(" = 0");
369 return 0;
370
Al Virob42d5702013-11-22 01:53:47 -0500371error_tree:
David Howellsf044c882017-11-02 15:27:45 +0000372 remove_proc_subtree(cell->name, net->proc_afs);
David Howellsec268152007-04-26 15:49:28 -0700373error_dir:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 _leave(" = -ENOMEM");
375 return -ENOMEM;
David Howellsec268152007-04-26 15:49:28 -0700376}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378/*
379 * remove /proc/fs/afs/<cell>/
380 */
David Howellsf044c882017-11-02 15:27:45 +0000381void afs_proc_cell_remove(struct afs_net *net, struct afs_cell *cell)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382{
383 _enter("");
384
David Howellsf044c882017-11-02 15:27:45 +0000385 remove_proc_subtree(cell->name, net->proc_afs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
387 _leave("");
David Howellsec268152007-04-26 15:49:28 -0700388}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390/*
391 * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells
392 */
393static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file)
394{
395 struct afs_cell *cell;
396 struct seq_file *m;
397 int ret;
398
Al Virod9dda782013-03-31 18:16:14 -0400399 cell = PDE_DATA(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 if (!cell)
401 return -ENOENT;
402
403 ret = seq_open(file, &afs_proc_cell_volumes_ops);
404 if (ret < 0)
405 return ret;
406
407 m = file->private_data;
408 m->private = cell;
409
410 return 0;
David Howellsec268152007-04-26 15:49:28 -0700411}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 * set up the iterator to start reading from the cells list and return the
415 * first item
416 */
417static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
418{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 struct afs_cell *cell = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
421 _enter("cell=%p pos=%Ld", cell, *_pos);
422
423 /* lock the list against modification */
424 down_read(&cell->vl_sem);
Pavel Emelianova6a8bd62007-07-15 23:39:52 -0700425 return seq_list_start_head(&cell->vl_list, *_pos);
David Howellsec268152007-04-26 15:49:28 -0700426}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428/*
429 * move to next cell in cells list
430 */
431static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
432 loff_t *_pos)
433{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 struct afs_cell *cell = p->private;
435
436 _enter("cell=%p pos=%Ld", cell, *_pos);
Pavel Emelianova6a8bd62007-07-15 23:39:52 -0700437 return seq_list_next(v, &cell->vl_list, _pos);
David Howellsec268152007-04-26 15:49:28 -0700438}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440/*
441 * clean up after reading from the cells list
442 */
443static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v)
444{
445 struct afs_cell *cell = p->private;
446
447 up_read(&cell->vl_sem);
David Howellsec268152007-04-26 15:49:28 -0700448}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
Adrian Bunkc1206a22007-10-16 23:26:41 -0700450static const char afs_vlocation_states[][4] = {
David Howells08e0e7c2007-04-26 15:55:03 -0700451 [AFS_VL_NEW] = "New",
452 [AFS_VL_CREATING] = "Crt",
453 [AFS_VL_VALID] = "Val",
454 [AFS_VL_NO_VOLUME] = "NoV",
455 [AFS_VL_UPDATING] = "Upd",
456 [AFS_VL_VOLUME_DELETED] = "Del",
457 [AFS_VL_UNCERTAIN] = "Unc",
458};
459
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460/*
461 * display a header line followed by a load of volume lines
462 */
463static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
464{
Pavel Emelianova6a8bd62007-07-15 23:39:52 -0700465 struct afs_cell *cell = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 struct afs_vlocation *vlocation =
467 list_entry(v, struct afs_vlocation, link);
468
469 /* display header on line 1 */
Pavel Emelianova6a8bd62007-07-15 23:39:52 -0700470 if (v == &cell->vl_list) {
David Howells08e0e7c2007-04-26 15:55:03 -0700471 seq_puts(m, "USE STT VLID[0] VLID[1] VLID[2] NAME\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 return 0;
473 }
474
475 /* display one cell per line on subsequent lines */
David Howells08e0e7c2007-04-26 15:55:03 -0700476 seq_printf(m, "%3d %s %08x %08x %08x %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 atomic_read(&vlocation->usage),
David Howells08e0e7c2007-04-26 15:55:03 -0700478 afs_vlocation_states[vlocation->state],
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 vlocation->vldb.vid[0],
480 vlocation->vldb.vid[1],
481 vlocation->vldb.vid[2],
David Howellsec268152007-04-26 15:49:28 -0700482 vlocation->vldb.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
484 return 0;
David Howellsec268152007-04-26 15:49:28 -0700485}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487/*
488 * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume
489 * location server
490 */
491static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file)
492{
493 struct afs_cell *cell;
494 struct seq_file *m;
495 int ret;
496
Al Virod9dda782013-03-31 18:16:14 -0400497 cell = PDE_DATA(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 if (!cell)
499 return -ENOENT;
500
David Howells08e0e7c2007-04-26 15:55:03 -0700501 ret = seq_open(file, &afs_proc_cell_vlservers_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 if (ret<0)
503 return ret;
504
505 m = file->private_data;
506 m->private = cell;
507
508 return 0;
David Howellsec268152007-04-26 15:49:28 -0700509}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 * set up the iterator to start reading from the cells list and return the
513 * first item
514 */
515static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
516{
David Howells8b2a4642017-11-02 15:27:50 +0000517 struct afs_addr_list *alist;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 struct afs_cell *cell = m->private;
519 loff_t pos = *_pos;
520
David Howells8b2a4642017-11-02 15:27:50 +0000521 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
David Howells8b2a4642017-11-02 15:27:50 +0000523 alist = rcu_dereference(cell->vl_addrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
525 /* allow for the header line */
526 if (!pos)
527 return (void *) 1;
528 pos--;
529
David Howells8b2a4642017-11-02 15:27:50 +0000530 if (!alist || pos >= alist->nr_addrs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 return NULL;
532
David Howells8b2a4642017-11-02 15:27:50 +0000533 return alist->addrs + pos;
David Howellsec268152007-04-26 15:49:28 -0700534}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536/*
537 * move to next cell in cells list
538 */
539static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
540 loff_t *_pos)
541{
David Howells8b2a4642017-11-02 15:27:50 +0000542 struct afs_addr_list *alist;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 struct afs_cell *cell = p->private;
544 loff_t pos;
545
David Howells8b2a4642017-11-02 15:27:50 +0000546 alist = rcu_dereference(cell->vl_addrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
548 pos = *_pos;
549 (*_pos)++;
David Howells8b2a4642017-11-02 15:27:50 +0000550 if (!alist || pos >= alist->nr_addrs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 return NULL;
552
David Howells8b2a4642017-11-02 15:27:50 +0000553 return alist->addrs + pos;
David Howellsec268152007-04-26 15:49:28 -0700554}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556/*
557 * clean up after reading from the cells list
558 */
559static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v)
560{
David Howells8b2a4642017-11-02 15:27:50 +0000561 rcu_read_unlock();
David Howellsec268152007-04-26 15:49:28 -0700562}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564/*
565 * display a header line followed by a load of volume lines
566 */
567static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
568{
David Howells4d9df982017-11-02 15:27:47 +0000569 struct sockaddr_rxrpc *addr = v;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
571 /* display header on line 1 */
David Howells4d9df982017-11-02 15:27:47 +0000572 if (v == (void *)1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 seq_puts(m, "ADDRESS\n");
574 return 0;
575 }
576
577 /* display one cell per line on subsequent lines */
David Howells4d9df982017-11-02 15:27:47 +0000578 seq_printf(m, "%pISp\n", &addr->transport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 return 0;
David Howellsec268152007-04-26 15:49:28 -0700580}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582/*
583 * open "/proc/fs/afs/<cell>/servers" which provides a summary of active
584 * servers
585 */
586static int afs_proc_cell_servers_open(struct inode *inode, struct file *file)
587{
588 struct afs_cell *cell;
589 struct seq_file *m;
590 int ret;
591
Al Virod9dda782013-03-31 18:16:14 -0400592 cell = PDE_DATA(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 if (!cell)
594 return -ENOENT;
595
596 ret = seq_open(file, &afs_proc_cell_servers_ops);
597 if (ret < 0)
598 return ret;
599
600 m = file->private_data;
601 m->private = cell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 return 0;
David Howellsec268152007-04-26 15:49:28 -0700603}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 * set up the iterator to start reading from the cells list and return the
607 * first item
608 */
609static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos)
David Howells08e0e7c2007-04-26 15:55:03 -0700610 __acquires(m->private->servers_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 struct afs_cell *cell = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
614 _enter("cell=%p pos=%Ld", cell, *_pos);
615
616 /* lock the list against modification */
David Howells08e0e7c2007-04-26 15:55:03 -0700617 read_lock(&cell->servers_lock);
Pavel Emelianova6a8bd62007-07-15 23:39:52 -0700618 return seq_list_start_head(&cell->servers, *_pos);
David Howellsec268152007-04-26 15:49:28 -0700619}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621/*
622 * move to next cell in cells list
623 */
624static void *afs_proc_cell_servers_next(struct seq_file *p, void *v,
625 loff_t *_pos)
626{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 struct afs_cell *cell = p->private;
628
629 _enter("cell=%p pos=%Ld", cell, *_pos);
Pavel Emelianova6a8bd62007-07-15 23:39:52 -0700630 return seq_list_next(v, &cell->servers, _pos);
David Howellsec268152007-04-26 15:49:28 -0700631}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633/*
634 * clean up after reading from the cells list
635 */
636static void afs_proc_cell_servers_stop(struct seq_file *p, void *v)
David Howells08e0e7c2007-04-26 15:55:03 -0700637 __releases(p->private->servers_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638{
639 struct afs_cell *cell = p->private;
640
David Howells08e0e7c2007-04-26 15:55:03 -0700641 read_unlock(&cell->servers_lock);
David Howellsec268152007-04-26 15:49:28 -0700642}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644/*
645 * display a header line followed by a load of volume lines
646 */
647static int afs_proc_cell_servers_show(struct seq_file *m, void *v)
648{
Pavel Emelianova6a8bd62007-07-15 23:39:52 -0700649 struct afs_cell *cell = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 struct afs_server *server = list_entry(v, struct afs_server, link);
David Howells4d9df982017-11-02 15:27:47 +0000651 char ipaddr[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653 /* display header on line 1 */
Pavel Emelianova6a8bd62007-07-15 23:39:52 -0700654 if (v == &cell->servers) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 seq_puts(m, "USE ADDR STATE\n");
656 return 0;
657 }
658
659 /* display one cell per line on subsequent lines */
David Howells8b2a4642017-11-02 15:27:50 +0000660 sprintf(ipaddr, "%pISp", &server->addrs->addrs[0].transport);
David Howells3838d3e2017-11-02 15:27:47 +0000661 seq_printf(m, "%3d %-15s %5d\n",
David Howellsec268152007-04-26 15:49:28 -0700662 atomic_read(&server->usage), ipaddr, server->fs_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
664 return 0;
David Howellsec268152007-04-26 15:49:28 -0700665}