blob: c9343346034807827fd25c64b20d43e628029c9f [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
189 down_read(&net->proc_cells_sem);
190 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 Howellsf044c882017-11-02 15:27:45 +0000208 struct afs_net *net = afs_seq2net(m);
209
210 up_read(&net->proc_cells_sem);
David Howellsec268152007-04-26 15:49:28 -0700211}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213/*
214 * display a header line followed by a load of cell lines
215 */
216static int afs_proc_cells_show(struct seq_file *m, void *v)
217{
218 struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
David Howellsf044c882017-11-02 15:27:45 +0000219 struct afs_net *net = afs_seq2net(m);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
David Howellsf044c882017-11-02 15:27:45 +0000221 if (v == &net->proc_cells) {
David Howellsec268152007-04-26 15:49:28 -0700222 /* display header on line 1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 seq_puts(m, "USE NAME\n");
224 return 0;
225 }
226
227 /* display one cell per line on subsequent lines */
David Howellsec268152007-04-26 15:49:28 -0700228 seq_printf(m, "%3d %s\n",
229 atomic_read(&cell->usage), cell->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 return 0;
David Howellsec268152007-04-26 15:49:28 -0700231}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233/*
234 * handle writes to /proc/fs/afs/cells
235 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
236 */
237static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
238 size_t size, loff_t *_pos)
239{
David Howellsf044c882017-11-02 15:27:45 +0000240 struct afs_net *net = afs_proc2net(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 char *kbuf, *name, *args;
242 int ret;
243
244 /* start by dragging the command into memory */
245 if (size <= 1 || size >= PAGE_SIZE)
246 return -EINVAL;
247
Al Viro16e5c1f2015-12-24 00:06:05 -0500248 kbuf = memdup_user_nul(buf, size);
249 if (IS_ERR(kbuf))
250 return PTR_ERR(kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
252 /* trim to first NL */
253 name = memchr(kbuf, '\n', size);
254 if (name)
255 *name = 0;
256
257 /* split into command, name and argslist */
258 name = strchr(kbuf, ' ');
259 if (!name)
260 goto inval;
261 do {
262 *name++ = 0;
263 } while(*name == ' ');
264 if (!*name)
265 goto inval;
266
267 args = strchr(name, ' ');
268 if (!args)
269 goto inval;
270 do {
271 *args++ = 0;
272 } while(*args == ' ');
273 if (!*args)
274 goto inval;
275
276 /* determine command to perform */
277 _debug("cmd=%s name=%s args=%s", kbuf, name, args);
278
279 if (strcmp(kbuf, "add") == 0) {
280 struct afs_cell *cell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
David Howellsf044c882017-11-02 15:27:45 +0000282 cell = afs_cell_create(net, name, strlen(name), args, false);
David Howells08e0e7c2007-04-26 15:55:03 -0700283 if (IS_ERR(cell)) {
284 ret = PTR_ERR(cell);
285 goto done;
286 }
287
288 afs_put_cell(cell);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 printk("kAFS: Added new cell '%s'\n", name);
David Howellsec268152007-04-26 15:49:28 -0700290 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 goto inval;
292 }
293
294 ret = size;
295
David Howellsec268152007-04-26 15:49:28 -0700296done:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 kfree(kbuf);
298 _leave(" = %d", ret);
299 return ret;
300
David Howellsec268152007-04-26 15:49:28 -0700301inval:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 ret = -EINVAL;
303 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
304 goto done;
David Howellsec268152007-04-26 15:49:28 -0700305}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
308 size_t size, loff_t *_pos)
309{
310 return 0;
311}
312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313/*
314 * handle writes to /proc/fs/afs/rootcell
315 * - to initialize rootcell: echo "cell.name:192.168.231.14"
316 */
317static ssize_t afs_proc_rootcell_write(struct file *file,
318 const char __user *buf,
319 size_t size, loff_t *_pos)
320{
David Howellsf044c882017-11-02 15:27:45 +0000321 struct afs_net *net = afs_proc2net(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 char *kbuf, *s;
323 int ret;
324
325 /* start by dragging the command into memory */
326 if (size <= 1 || size >= PAGE_SIZE)
327 return -EINVAL;
328
Al Viro16e5c1f2015-12-24 00:06:05 -0500329 kbuf = memdup_user_nul(buf, size);
330 if (IS_ERR(kbuf))
331 return PTR_ERR(kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
333 /* trim to first NL */
334 s = memchr(kbuf, '\n', size);
335 if (s)
336 *s = 0;
337
338 /* determine command to perform */
339 _debug("rootcell=%s", kbuf);
340
David Howellsf044c882017-11-02 15:27:45 +0000341 ret = afs_cell_init(net, kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 if (ret >= 0)
343 ret = size; /* consume everything, always */
344
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 kfree(kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 _leave(" = %d", ret);
347 return ret;
David Howellsec268152007-04-26 15:49:28 -0700348}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350/*
351 * initialise /proc/fs/afs/<cell>/
352 */
David Howellsf044c882017-11-02 15:27:45 +0000353int afs_proc_cell_setup(struct afs_net *net, struct afs_cell *cell)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
Al Virob42d5702013-11-22 01:53:47 -0500355 struct proc_dir_entry *dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
357 _enter("%p{%s}", cell, cell->name);
358
David Howellsf044c882017-11-02 15:27:45 +0000359 dir = proc_mkdir(cell->name, net->proc_afs);
Al Virob42d5702013-11-22 01:53:47 -0500360 if (!dir)
David Howellsec268152007-04-26 15:49:28 -0700361 goto error_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
Al Virob42d5702013-11-22 01:53:47 -0500363 if (!proc_create_data("servers", 0, dir,
364 &afs_proc_cell_servers_fops, cell) ||
365 !proc_create_data("vlservers", 0, dir,
366 &afs_proc_cell_vlservers_fops, cell) ||
367 !proc_create_data("volumes", 0, dir,
368 &afs_proc_cell_volumes_fops, cell))
369 goto error_tree;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371 _leave(" = 0");
372 return 0;
373
Al Virob42d5702013-11-22 01:53:47 -0500374error_tree:
David Howellsf044c882017-11-02 15:27:45 +0000375 remove_proc_subtree(cell->name, net->proc_afs);
David Howellsec268152007-04-26 15:49:28 -0700376error_dir:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 _leave(" = -ENOMEM");
378 return -ENOMEM;
David Howellsec268152007-04-26 15:49:28 -0700379}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381/*
382 * remove /proc/fs/afs/<cell>/
383 */
David Howellsf044c882017-11-02 15:27:45 +0000384void afs_proc_cell_remove(struct afs_net *net, struct afs_cell *cell)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385{
386 _enter("");
387
David Howellsf044c882017-11-02 15:27:45 +0000388 remove_proc_subtree(cell->name, net->proc_afs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
390 _leave("");
David Howellsec268152007-04-26 15:49:28 -0700391}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393/*
394 * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells
395 */
396static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file)
397{
398 struct afs_cell *cell;
399 struct seq_file *m;
400 int ret;
401
Al Virod9dda782013-03-31 18:16:14 -0400402 cell = PDE_DATA(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 if (!cell)
404 return -ENOENT;
405
406 ret = seq_open(file, &afs_proc_cell_volumes_ops);
407 if (ret < 0)
408 return ret;
409
410 m = file->private_data;
411 m->private = cell;
412
413 return 0;
David Howellsec268152007-04-26 15:49:28 -0700414}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 * set up the iterator to start reading from the cells list and return the
418 * first item
419 */
420static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
421{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 struct afs_cell *cell = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
424 _enter("cell=%p pos=%Ld", cell, *_pos);
425
426 /* lock the list against modification */
427 down_read(&cell->vl_sem);
Pavel Emelianova6a8bd62007-07-15 23:39:52 -0700428 return seq_list_start_head(&cell->vl_list, *_pos);
David Howellsec268152007-04-26 15:49:28 -0700429}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431/*
432 * move to next cell in cells list
433 */
434static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
435 loff_t *_pos)
436{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 struct afs_cell *cell = p->private;
438
439 _enter("cell=%p pos=%Ld", cell, *_pos);
Pavel Emelianova6a8bd62007-07-15 23:39:52 -0700440 return seq_list_next(v, &cell->vl_list, _pos);
David Howellsec268152007-04-26 15:49:28 -0700441}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443/*
444 * clean up after reading from the cells list
445 */
446static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v)
447{
448 struct afs_cell *cell = p->private;
449
450 up_read(&cell->vl_sem);
David Howellsec268152007-04-26 15:49:28 -0700451}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
Adrian Bunkc1206a22007-10-16 23:26:41 -0700453static const char afs_vlocation_states[][4] = {
David Howells08e0e7c2007-04-26 15:55:03 -0700454 [AFS_VL_NEW] = "New",
455 [AFS_VL_CREATING] = "Crt",
456 [AFS_VL_VALID] = "Val",
457 [AFS_VL_NO_VOLUME] = "NoV",
458 [AFS_VL_UPDATING] = "Upd",
459 [AFS_VL_VOLUME_DELETED] = "Del",
460 [AFS_VL_UNCERTAIN] = "Unc",
461};
462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463/*
464 * display a header line followed by a load of volume lines
465 */
466static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
467{
Pavel Emelianova6a8bd62007-07-15 23:39:52 -0700468 struct afs_cell *cell = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 struct afs_vlocation *vlocation =
470 list_entry(v, struct afs_vlocation, link);
471
472 /* display header on line 1 */
Pavel Emelianova6a8bd62007-07-15 23:39:52 -0700473 if (v == &cell->vl_list) {
David Howells08e0e7c2007-04-26 15:55:03 -0700474 seq_puts(m, "USE STT VLID[0] VLID[1] VLID[2] NAME\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 return 0;
476 }
477
478 /* display one cell per line on subsequent lines */
David Howells08e0e7c2007-04-26 15:55:03 -0700479 seq_printf(m, "%3d %s %08x %08x %08x %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 atomic_read(&vlocation->usage),
David Howells08e0e7c2007-04-26 15:55:03 -0700481 afs_vlocation_states[vlocation->state],
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 vlocation->vldb.vid[0],
483 vlocation->vldb.vid[1],
484 vlocation->vldb.vid[2],
David Howellsec268152007-04-26 15:49:28 -0700485 vlocation->vldb.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
487 return 0;
David Howellsec268152007-04-26 15:49:28 -0700488}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490/*
491 * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume
492 * location server
493 */
494static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file)
495{
496 struct afs_cell *cell;
497 struct seq_file *m;
498 int ret;
499
Al Virod9dda782013-03-31 18:16:14 -0400500 cell = PDE_DATA(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 if (!cell)
502 return -ENOENT;
503
David Howells08e0e7c2007-04-26 15:55:03 -0700504 ret = seq_open(file, &afs_proc_cell_vlservers_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 if (ret<0)
506 return ret;
507
508 m = file->private_data;
509 m->private = cell;
510
511 return 0;
David Howellsec268152007-04-26 15:49:28 -0700512}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 * set up the iterator to start reading from the cells list and return the
516 * first item
517 */
518static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
519{
520 struct afs_cell *cell = m->private;
521 loff_t pos = *_pos;
522
523 _enter("cell=%p pos=%Ld", cell, *_pos);
524
525 /* lock the list against modification */
526 down_read(&cell->vl_sem);
527
528 /* allow for the header line */
529 if (!pos)
530 return (void *) 1;
531 pos--;
532
533 if (pos >= cell->vl_naddrs)
534 return NULL;
535
536 return &cell->vl_addrs[pos];
David Howellsec268152007-04-26 15:49:28 -0700537}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539/*
540 * move to next cell in cells list
541 */
542static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
543 loff_t *_pos)
544{
545 struct afs_cell *cell = p->private;
546 loff_t pos;
547
548 _enter("cell=%p{nad=%u} pos=%Ld", cell, cell->vl_naddrs, *_pos);
549
550 pos = *_pos;
551 (*_pos)++;
552 if (pos >= cell->vl_naddrs)
553 return NULL;
554
555 return &cell->vl_addrs[pos];
David Howellsec268152007-04-26 15:49:28 -0700556}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558/*
559 * clean up after reading from the cells list
560 */
561static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v)
562{
563 struct afs_cell *cell = p->private;
564
565 up_read(&cell->vl_sem);
David Howellsec268152007-04-26 15:49:28 -0700566}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568/*
569 * display a header line followed by a load of volume lines
570 */
571static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
572{
573 struct in_addr *addr = v;
574
575 /* display header on line 1 */
576 if (v == (struct in_addr *) 1) {
577 seq_puts(m, "ADDRESS\n");
578 return 0;
579 }
580
581 /* display one cell per line on subsequent lines */
Harvey Harrisonbe859402008-10-31 00:56:28 -0700582 seq_printf(m, "%pI4\n", &addr->s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 return 0;
David Howellsec268152007-04-26 15:49:28 -0700584}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586/*
587 * open "/proc/fs/afs/<cell>/servers" which provides a summary of active
588 * servers
589 */
590static int afs_proc_cell_servers_open(struct inode *inode, struct file *file)
591{
592 struct afs_cell *cell;
593 struct seq_file *m;
594 int ret;
595
Al Virod9dda782013-03-31 18:16:14 -0400596 cell = PDE_DATA(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 if (!cell)
598 return -ENOENT;
599
600 ret = seq_open(file, &afs_proc_cell_servers_ops);
601 if (ret < 0)
602 return ret;
603
604 m = file->private_data;
605 m->private = cell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 return 0;
David Howellsec268152007-04-26 15:49:28 -0700607}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 * set up the iterator to start reading from the cells list and return the
611 * first item
612 */
613static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos)
David Howells08e0e7c2007-04-26 15:55:03 -0700614 __acquires(m->private->servers_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 struct afs_cell *cell = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618 _enter("cell=%p pos=%Ld", cell, *_pos);
619
620 /* lock the list against modification */
David Howells08e0e7c2007-04-26 15:55:03 -0700621 read_lock(&cell->servers_lock);
Pavel Emelianova6a8bd62007-07-15 23:39:52 -0700622 return seq_list_start_head(&cell->servers, *_pos);
David Howellsec268152007-04-26 15:49:28 -0700623}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625/*
626 * move to next cell in cells list
627 */
628static void *afs_proc_cell_servers_next(struct seq_file *p, void *v,
629 loff_t *_pos)
630{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 struct afs_cell *cell = p->private;
632
633 _enter("cell=%p pos=%Ld", cell, *_pos);
Pavel Emelianova6a8bd62007-07-15 23:39:52 -0700634 return seq_list_next(v, &cell->servers, _pos);
David Howellsec268152007-04-26 15:49:28 -0700635}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637/*
638 * clean up after reading from the cells list
639 */
640static void afs_proc_cell_servers_stop(struct seq_file *p, void *v)
David Howells08e0e7c2007-04-26 15:55:03 -0700641 __releases(p->private->servers_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642{
643 struct afs_cell *cell = p->private;
644
David Howells08e0e7c2007-04-26 15:55:03 -0700645 read_unlock(&cell->servers_lock);
David Howellsec268152007-04-26 15:49:28 -0700646}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648/*
649 * display a header line followed by a load of volume lines
650 */
651static int afs_proc_cell_servers_show(struct seq_file *m, void *v)
652{
Pavel Emelianova6a8bd62007-07-15 23:39:52 -0700653 struct afs_cell *cell = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 struct afs_server *server = list_entry(v, struct afs_server, link);
655 char ipaddr[20];
656
657 /* display header on line 1 */
Pavel Emelianova6a8bd62007-07-15 23:39:52 -0700658 if (v == &cell->servers) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 seq_puts(m, "USE ADDR STATE\n");
660 return 0;
661 }
662
663 /* display one cell per line on subsequent lines */
Harvey Harrisonbe859402008-10-31 00:56:28 -0700664 sprintf(ipaddr, "%pI4", &server->addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 seq_printf(m, "%3d %-15.15s %5d\n",
David Howellsec268152007-04-26 15:49:28 -0700666 atomic_read(&server->usage), ipaddr, server->fs_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
668 return 0;
David Howellsec268152007-04-26 15:49:28 -0700669}