Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/fs/afs/proc.c
15109 views
1
/* /proc interface for AFS
2
*
3
* Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4
* Written by David Howells ([email protected])
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
12
#include <linux/slab.h>
13
#include <linux/module.h>
14
#include <linux/proc_fs.h>
15
#include <linux/seq_file.h>
16
#include <linux/sched.h>
17
#include <asm/uaccess.h>
18
#include "internal.h"
19
20
static struct proc_dir_entry *proc_afs;
21
22
23
static int afs_proc_cells_open(struct inode *inode, struct file *file);
24
static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos);
25
static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos);
26
static void afs_proc_cells_stop(struct seq_file *p, void *v);
27
static int afs_proc_cells_show(struct seq_file *m, void *v);
28
static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
29
size_t size, loff_t *_pos);
30
31
static const struct seq_operations afs_proc_cells_ops = {
32
.start = afs_proc_cells_start,
33
.next = afs_proc_cells_next,
34
.stop = afs_proc_cells_stop,
35
.show = afs_proc_cells_show,
36
};
37
38
static const struct file_operations afs_proc_cells_fops = {
39
.open = afs_proc_cells_open,
40
.read = seq_read,
41
.write = afs_proc_cells_write,
42
.llseek = seq_lseek,
43
.release = seq_release,
44
.owner = THIS_MODULE,
45
};
46
47
static int afs_proc_rootcell_open(struct inode *inode, struct file *file);
48
static int afs_proc_rootcell_release(struct inode *inode, struct file *file);
49
static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
50
size_t size, loff_t *_pos);
51
static ssize_t afs_proc_rootcell_write(struct file *file,
52
const char __user *buf,
53
size_t size, loff_t *_pos);
54
55
static const struct file_operations afs_proc_rootcell_fops = {
56
.open = afs_proc_rootcell_open,
57
.read = afs_proc_rootcell_read,
58
.write = afs_proc_rootcell_write,
59
.llseek = no_llseek,
60
.release = afs_proc_rootcell_release,
61
.owner = THIS_MODULE,
62
};
63
64
static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file);
65
static int afs_proc_cell_volumes_release(struct inode *inode,
66
struct file *file);
67
static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos);
68
static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
69
loff_t *pos);
70
static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v);
71
static int afs_proc_cell_volumes_show(struct seq_file *m, void *v);
72
73
static const struct seq_operations afs_proc_cell_volumes_ops = {
74
.start = afs_proc_cell_volumes_start,
75
.next = afs_proc_cell_volumes_next,
76
.stop = afs_proc_cell_volumes_stop,
77
.show = afs_proc_cell_volumes_show,
78
};
79
80
static const struct file_operations afs_proc_cell_volumes_fops = {
81
.open = afs_proc_cell_volumes_open,
82
.read = seq_read,
83
.llseek = seq_lseek,
84
.release = afs_proc_cell_volumes_release,
85
.owner = THIS_MODULE,
86
};
87
88
static int afs_proc_cell_vlservers_open(struct inode *inode,
89
struct file *file);
90
static int afs_proc_cell_vlservers_release(struct inode *inode,
91
struct file *file);
92
static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos);
93
static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
94
loff_t *pos);
95
static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v);
96
static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v);
97
98
static const struct seq_operations afs_proc_cell_vlservers_ops = {
99
.start = afs_proc_cell_vlservers_start,
100
.next = afs_proc_cell_vlservers_next,
101
.stop = afs_proc_cell_vlservers_stop,
102
.show = afs_proc_cell_vlservers_show,
103
};
104
105
static const struct file_operations afs_proc_cell_vlservers_fops = {
106
.open = afs_proc_cell_vlservers_open,
107
.read = seq_read,
108
.llseek = seq_lseek,
109
.release = afs_proc_cell_vlservers_release,
110
.owner = THIS_MODULE,
111
};
112
113
static int afs_proc_cell_servers_open(struct inode *inode, struct file *file);
114
static int afs_proc_cell_servers_release(struct inode *inode,
115
struct file *file);
116
static void *afs_proc_cell_servers_start(struct seq_file *p, loff_t *pos);
117
static void *afs_proc_cell_servers_next(struct seq_file *p, void *v,
118
loff_t *pos);
119
static void afs_proc_cell_servers_stop(struct seq_file *p, void *v);
120
static int afs_proc_cell_servers_show(struct seq_file *m, void *v);
121
122
static const struct seq_operations afs_proc_cell_servers_ops = {
123
.start = afs_proc_cell_servers_start,
124
.next = afs_proc_cell_servers_next,
125
.stop = afs_proc_cell_servers_stop,
126
.show = afs_proc_cell_servers_show,
127
};
128
129
static const struct file_operations afs_proc_cell_servers_fops = {
130
.open = afs_proc_cell_servers_open,
131
.read = seq_read,
132
.llseek = seq_lseek,
133
.release = afs_proc_cell_servers_release,
134
.owner = THIS_MODULE,
135
};
136
137
/*
138
* initialise the /proc/fs/afs/ directory
139
*/
140
int afs_proc_init(void)
141
{
142
struct proc_dir_entry *p;
143
144
_enter("");
145
146
proc_afs = proc_mkdir("fs/afs", NULL);
147
if (!proc_afs)
148
goto error_dir;
149
150
p = proc_create("cells", 0, proc_afs, &afs_proc_cells_fops);
151
if (!p)
152
goto error_cells;
153
154
p = proc_create("rootcell", 0, proc_afs, &afs_proc_rootcell_fops);
155
if (!p)
156
goto error_rootcell;
157
158
_leave(" = 0");
159
return 0;
160
161
error_rootcell:
162
remove_proc_entry("cells", proc_afs);
163
error_cells:
164
remove_proc_entry("fs/afs", NULL);
165
error_dir:
166
_leave(" = -ENOMEM");
167
return -ENOMEM;
168
}
169
170
/*
171
* clean up the /proc/fs/afs/ directory
172
*/
173
void afs_proc_cleanup(void)
174
{
175
remove_proc_entry("rootcell", proc_afs);
176
remove_proc_entry("cells", proc_afs);
177
remove_proc_entry("fs/afs", NULL);
178
}
179
180
/*
181
* open "/proc/fs/afs/cells" which provides a summary of extant cells
182
*/
183
static int afs_proc_cells_open(struct inode *inode, struct file *file)
184
{
185
struct seq_file *m;
186
int ret;
187
188
ret = seq_open(file, &afs_proc_cells_ops);
189
if (ret < 0)
190
return ret;
191
192
m = file->private_data;
193
m->private = PDE(inode)->data;
194
195
return 0;
196
}
197
198
/*
199
* set up the iterator to start reading from the cells list and return the
200
* first item
201
*/
202
static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
203
{
204
/* lock the list against modification */
205
down_read(&afs_proc_cells_sem);
206
return seq_list_start_head(&afs_proc_cells, *_pos);
207
}
208
209
/*
210
* move to next cell in cells list
211
*/
212
static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos)
213
{
214
return seq_list_next(v, &afs_proc_cells, pos);
215
}
216
217
/*
218
* clean up after reading from the cells list
219
*/
220
static void afs_proc_cells_stop(struct seq_file *p, void *v)
221
{
222
up_read(&afs_proc_cells_sem);
223
}
224
225
/*
226
* display a header line followed by a load of cell lines
227
*/
228
static int afs_proc_cells_show(struct seq_file *m, void *v)
229
{
230
struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
231
232
if (v == &afs_proc_cells) {
233
/* display header on line 1 */
234
seq_puts(m, "USE NAME\n");
235
return 0;
236
}
237
238
/* display one cell per line on subsequent lines */
239
seq_printf(m, "%3d %s\n",
240
atomic_read(&cell->usage), cell->name);
241
return 0;
242
}
243
244
/*
245
* handle writes to /proc/fs/afs/cells
246
* - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
247
*/
248
static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
249
size_t size, loff_t *_pos)
250
{
251
char *kbuf, *name, *args;
252
int ret;
253
254
/* start by dragging the command into memory */
255
if (size <= 1 || size >= PAGE_SIZE)
256
return -EINVAL;
257
258
kbuf = kmalloc(size + 1, GFP_KERNEL);
259
if (!kbuf)
260
return -ENOMEM;
261
262
ret = -EFAULT;
263
if (copy_from_user(kbuf, buf, size) != 0)
264
goto done;
265
kbuf[size] = 0;
266
267
/* trim to first NL */
268
name = memchr(kbuf, '\n', size);
269
if (name)
270
*name = 0;
271
272
/* split into command, name and argslist */
273
name = strchr(kbuf, ' ');
274
if (!name)
275
goto inval;
276
do {
277
*name++ = 0;
278
} while(*name == ' ');
279
if (!*name)
280
goto inval;
281
282
args = strchr(name, ' ');
283
if (!args)
284
goto inval;
285
do {
286
*args++ = 0;
287
} while(*args == ' ');
288
if (!*args)
289
goto inval;
290
291
/* determine command to perform */
292
_debug("cmd=%s name=%s args=%s", kbuf, name, args);
293
294
if (strcmp(kbuf, "add") == 0) {
295
struct afs_cell *cell;
296
297
cell = afs_cell_create(name, strlen(name), args, false);
298
if (IS_ERR(cell)) {
299
ret = PTR_ERR(cell);
300
goto done;
301
}
302
303
afs_put_cell(cell);
304
printk("kAFS: Added new cell '%s'\n", name);
305
} else {
306
goto inval;
307
}
308
309
ret = size;
310
311
done:
312
kfree(kbuf);
313
_leave(" = %d", ret);
314
return ret;
315
316
inval:
317
ret = -EINVAL;
318
printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
319
goto done;
320
}
321
322
/*
323
* Stubs for /proc/fs/afs/rootcell
324
*/
325
static int afs_proc_rootcell_open(struct inode *inode, struct file *file)
326
{
327
return 0;
328
}
329
330
static int afs_proc_rootcell_release(struct inode *inode, struct file *file)
331
{
332
return 0;
333
}
334
335
static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
336
size_t size, loff_t *_pos)
337
{
338
return 0;
339
}
340
341
/*
342
* handle writes to /proc/fs/afs/rootcell
343
* - to initialize rootcell: echo "cell.name:192.168.231.14"
344
*/
345
static ssize_t afs_proc_rootcell_write(struct file *file,
346
const char __user *buf,
347
size_t size, loff_t *_pos)
348
{
349
char *kbuf, *s;
350
int ret;
351
352
/* start by dragging the command into memory */
353
if (size <= 1 || size >= PAGE_SIZE)
354
return -EINVAL;
355
356
ret = -ENOMEM;
357
kbuf = kmalloc(size + 1, GFP_KERNEL);
358
if (!kbuf)
359
goto nomem;
360
361
ret = -EFAULT;
362
if (copy_from_user(kbuf, buf, size) != 0)
363
goto infault;
364
kbuf[size] = 0;
365
366
/* trim to first NL */
367
s = memchr(kbuf, '\n', size);
368
if (s)
369
*s = 0;
370
371
/* determine command to perform */
372
_debug("rootcell=%s", kbuf);
373
374
ret = afs_cell_init(kbuf);
375
if (ret >= 0)
376
ret = size; /* consume everything, always */
377
378
infault:
379
kfree(kbuf);
380
nomem:
381
_leave(" = %d", ret);
382
return ret;
383
}
384
385
/*
386
* initialise /proc/fs/afs/<cell>/
387
*/
388
int afs_proc_cell_setup(struct afs_cell *cell)
389
{
390
struct proc_dir_entry *p;
391
392
_enter("%p{%s}", cell, cell->name);
393
394
cell->proc_dir = proc_mkdir(cell->name, proc_afs);
395
if (!cell->proc_dir)
396
goto error_dir;
397
398
p = proc_create_data("servers", 0, cell->proc_dir,
399
&afs_proc_cell_servers_fops, cell);
400
if (!p)
401
goto error_servers;
402
403
p = proc_create_data("vlservers", 0, cell->proc_dir,
404
&afs_proc_cell_vlservers_fops, cell);
405
if (!p)
406
goto error_vlservers;
407
408
p = proc_create_data("volumes", 0, cell->proc_dir,
409
&afs_proc_cell_volumes_fops, cell);
410
if (!p)
411
goto error_volumes;
412
413
_leave(" = 0");
414
return 0;
415
416
error_volumes:
417
remove_proc_entry("vlservers", cell->proc_dir);
418
error_vlservers:
419
remove_proc_entry("servers", cell->proc_dir);
420
error_servers:
421
remove_proc_entry(cell->name, proc_afs);
422
error_dir:
423
_leave(" = -ENOMEM");
424
return -ENOMEM;
425
}
426
427
/*
428
* remove /proc/fs/afs/<cell>/
429
*/
430
void afs_proc_cell_remove(struct afs_cell *cell)
431
{
432
_enter("");
433
434
remove_proc_entry("volumes", cell->proc_dir);
435
remove_proc_entry("vlservers", cell->proc_dir);
436
remove_proc_entry("servers", cell->proc_dir);
437
remove_proc_entry(cell->name, proc_afs);
438
439
_leave("");
440
}
441
442
/*
443
* open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells
444
*/
445
static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file)
446
{
447
struct afs_cell *cell;
448
struct seq_file *m;
449
int ret;
450
451
cell = PDE(inode)->data;
452
if (!cell)
453
return -ENOENT;
454
455
ret = seq_open(file, &afs_proc_cell_volumes_ops);
456
if (ret < 0)
457
return ret;
458
459
m = file->private_data;
460
m->private = cell;
461
462
return 0;
463
}
464
465
/*
466
* close the file and release the ref to the cell
467
*/
468
static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file)
469
{
470
return seq_release(inode, file);
471
}
472
473
/*
474
* set up the iterator to start reading from the cells list and return the
475
* first item
476
*/
477
static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
478
{
479
struct afs_cell *cell = m->private;
480
481
_enter("cell=%p pos=%Ld", cell, *_pos);
482
483
/* lock the list against modification */
484
down_read(&cell->vl_sem);
485
return seq_list_start_head(&cell->vl_list, *_pos);
486
}
487
488
/*
489
* move to next cell in cells list
490
*/
491
static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
492
loff_t *_pos)
493
{
494
struct afs_cell *cell = p->private;
495
496
_enter("cell=%p pos=%Ld", cell, *_pos);
497
return seq_list_next(v, &cell->vl_list, _pos);
498
}
499
500
/*
501
* clean up after reading from the cells list
502
*/
503
static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v)
504
{
505
struct afs_cell *cell = p->private;
506
507
up_read(&cell->vl_sem);
508
}
509
510
static const char afs_vlocation_states[][4] = {
511
[AFS_VL_NEW] = "New",
512
[AFS_VL_CREATING] = "Crt",
513
[AFS_VL_VALID] = "Val",
514
[AFS_VL_NO_VOLUME] = "NoV",
515
[AFS_VL_UPDATING] = "Upd",
516
[AFS_VL_VOLUME_DELETED] = "Del",
517
[AFS_VL_UNCERTAIN] = "Unc",
518
};
519
520
/*
521
* display a header line followed by a load of volume lines
522
*/
523
static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
524
{
525
struct afs_cell *cell = m->private;
526
struct afs_vlocation *vlocation =
527
list_entry(v, struct afs_vlocation, link);
528
529
/* display header on line 1 */
530
if (v == &cell->vl_list) {
531
seq_puts(m, "USE STT VLID[0] VLID[1] VLID[2] NAME\n");
532
return 0;
533
}
534
535
/* display one cell per line on subsequent lines */
536
seq_printf(m, "%3d %s %08x %08x %08x %s\n",
537
atomic_read(&vlocation->usage),
538
afs_vlocation_states[vlocation->state],
539
vlocation->vldb.vid[0],
540
vlocation->vldb.vid[1],
541
vlocation->vldb.vid[2],
542
vlocation->vldb.name);
543
544
return 0;
545
}
546
547
/*
548
* open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume
549
* location server
550
*/
551
static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file)
552
{
553
struct afs_cell *cell;
554
struct seq_file *m;
555
int ret;
556
557
cell = PDE(inode)->data;
558
if (!cell)
559
return -ENOENT;
560
561
ret = seq_open(file, &afs_proc_cell_vlservers_ops);
562
if (ret<0)
563
return ret;
564
565
m = file->private_data;
566
m->private = cell;
567
568
return 0;
569
}
570
571
/*
572
* close the file and release the ref to the cell
573
*/
574
static int afs_proc_cell_vlservers_release(struct inode *inode,
575
struct file *file)
576
{
577
return seq_release(inode, file);
578
}
579
580
/*
581
* set up the iterator to start reading from the cells list and return the
582
* first item
583
*/
584
static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
585
{
586
struct afs_cell *cell = m->private;
587
loff_t pos = *_pos;
588
589
_enter("cell=%p pos=%Ld", cell, *_pos);
590
591
/* lock the list against modification */
592
down_read(&cell->vl_sem);
593
594
/* allow for the header line */
595
if (!pos)
596
return (void *) 1;
597
pos--;
598
599
if (pos >= cell->vl_naddrs)
600
return NULL;
601
602
return &cell->vl_addrs[pos];
603
}
604
605
/*
606
* move to next cell in cells list
607
*/
608
static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
609
loff_t *_pos)
610
{
611
struct afs_cell *cell = p->private;
612
loff_t pos;
613
614
_enter("cell=%p{nad=%u} pos=%Ld", cell, cell->vl_naddrs, *_pos);
615
616
pos = *_pos;
617
(*_pos)++;
618
if (pos >= cell->vl_naddrs)
619
return NULL;
620
621
return &cell->vl_addrs[pos];
622
}
623
624
/*
625
* clean up after reading from the cells list
626
*/
627
static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v)
628
{
629
struct afs_cell *cell = p->private;
630
631
up_read(&cell->vl_sem);
632
}
633
634
/*
635
* display a header line followed by a load of volume lines
636
*/
637
static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
638
{
639
struct in_addr *addr = v;
640
641
/* display header on line 1 */
642
if (v == (struct in_addr *) 1) {
643
seq_puts(m, "ADDRESS\n");
644
return 0;
645
}
646
647
/* display one cell per line on subsequent lines */
648
seq_printf(m, "%pI4\n", &addr->s_addr);
649
return 0;
650
}
651
652
/*
653
* open "/proc/fs/afs/<cell>/servers" which provides a summary of active
654
* servers
655
*/
656
static int afs_proc_cell_servers_open(struct inode *inode, struct file *file)
657
{
658
struct afs_cell *cell;
659
struct seq_file *m;
660
int ret;
661
662
cell = PDE(inode)->data;
663
if (!cell)
664
return -ENOENT;
665
666
ret = seq_open(file, &afs_proc_cell_servers_ops);
667
if (ret < 0)
668
return ret;
669
670
m = file->private_data;
671
m->private = cell;
672
return 0;
673
}
674
675
/*
676
* close the file and release the ref to the cell
677
*/
678
static int afs_proc_cell_servers_release(struct inode *inode,
679
struct file *file)
680
{
681
return seq_release(inode, file);
682
}
683
684
/*
685
* set up the iterator to start reading from the cells list and return the
686
* first item
687
*/
688
static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos)
689
__acquires(m->private->servers_lock)
690
{
691
struct afs_cell *cell = m->private;
692
693
_enter("cell=%p pos=%Ld", cell, *_pos);
694
695
/* lock the list against modification */
696
read_lock(&cell->servers_lock);
697
return seq_list_start_head(&cell->servers, *_pos);
698
}
699
700
/*
701
* move to next cell in cells list
702
*/
703
static void *afs_proc_cell_servers_next(struct seq_file *p, void *v,
704
loff_t *_pos)
705
{
706
struct afs_cell *cell = p->private;
707
708
_enter("cell=%p pos=%Ld", cell, *_pos);
709
return seq_list_next(v, &cell->servers, _pos);
710
}
711
712
/*
713
* clean up after reading from the cells list
714
*/
715
static void afs_proc_cell_servers_stop(struct seq_file *p, void *v)
716
__releases(p->private->servers_lock)
717
{
718
struct afs_cell *cell = p->private;
719
720
read_unlock(&cell->servers_lock);
721
}
722
723
/*
724
* display a header line followed by a load of volume lines
725
*/
726
static int afs_proc_cell_servers_show(struct seq_file *m, void *v)
727
{
728
struct afs_cell *cell = m->private;
729
struct afs_server *server = list_entry(v, struct afs_server, link);
730
char ipaddr[20];
731
732
/* display header on line 1 */
733
if (v == &cell->servers) {
734
seq_puts(m, "USE ADDR STATE\n");
735
return 0;
736
}
737
738
/* display one cell per line on subsequent lines */
739
sprintf(ipaddr, "%pI4", &server->addr);
740
seq_printf(m, "%3d %-15.15s %5d\n",
741
atomic_read(&server->usage), ipaddr, server->fs_state);
742
743
return 0;
744
}
745
746