~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/afs/proc.c

Version: ~ [ linux-5.10-rc1 ] ~ [ linux-5.9.1 ] ~ [ linux-5.8.16 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.72 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.152 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.202 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.240 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.240 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* /proc interface for AFS
  2  *
  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 
 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 <linux/uaccess.h>
 18 #include "internal.h"
 19 
 20 static inline struct afs_net *afs_proc2net(struct file *f)
 21 {
 22         return &__afs_net;
 23 }
 24 
 25 static inline struct afs_net *afs_seq2net(struct seq_file *m)
 26 {
 27         return &__afs_net; // TODO: use seq_file_net(m)
 28 }
 29 
 30 static int afs_proc_cells_open(struct inode *inode, struct file *file);
 31 static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos);
 32 static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos);
 33 static void afs_proc_cells_stop(struct seq_file *p, void *v);
 34 static int afs_proc_cells_show(struct seq_file *m, void *v);
 35 static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
 36                                     size_t size, loff_t *_pos);
 37 
 38 static const struct seq_operations afs_proc_cells_ops = {
 39         .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 
 45 static const struct file_operations afs_proc_cells_fops = {
 46         .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 
 53 static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
 54                                       size_t size, loff_t *_pos);
 55 static ssize_t afs_proc_rootcell_write(struct file *file,
 56                                        const char __user *buf,
 57                                        size_t size, loff_t *_pos);
 58 
 59 static const struct file_operations afs_proc_rootcell_fops = {
 60         .read           = afs_proc_rootcell_read,
 61         .write          = afs_proc_rootcell_write,
 62         .llseek         = no_llseek,
 63 };
 64 
 65 static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file);
 66 static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos);
 67 static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
 68                                         loff_t *pos);
 69 static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v);
 70 static int afs_proc_cell_volumes_show(struct seq_file *m, void *v);
 71 
 72 static const struct seq_operations afs_proc_cell_volumes_ops = {
 73         .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 
 79 static const struct file_operations afs_proc_cell_volumes_fops = {
 80         .open           = afs_proc_cell_volumes_open,
 81         .read           = seq_read,
 82         .llseek         = seq_lseek,
 83         .release        = seq_release,
 84 };
 85 
 86 static int afs_proc_cell_vlservers_open(struct inode *inode,
 87                                         struct file *file);
 88 static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos);
 89 static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
 90                                           loff_t *pos);
 91 static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v);
 92 static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v);
 93 
 94 static const struct seq_operations afs_proc_cell_vlservers_ops = {
 95         .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 
101 static const struct file_operations afs_proc_cell_vlservers_fops = {
102         .open           = afs_proc_cell_vlservers_open,
103         .read           = seq_read,
104         .llseek         = seq_lseek,
105         .release        = seq_release,
106 };
107 
108 static int afs_proc_servers_open(struct inode *inode, struct file *file);
109 static void *afs_proc_servers_start(struct seq_file *p, loff_t *pos);
110 static void *afs_proc_servers_next(struct seq_file *p, void *v,
111                                         loff_t *pos);
112 static void afs_proc_servers_stop(struct seq_file *p, void *v);
113 static int afs_proc_servers_show(struct seq_file *m, void *v);
114 
115 static const struct seq_operations afs_proc_servers_ops = {
116         .start  = afs_proc_servers_start,
117         .next   = afs_proc_servers_next,
118         .stop   = afs_proc_servers_stop,
119         .show   = afs_proc_servers_show,
120 };
121 
122 static const struct file_operations afs_proc_servers_fops = {
123         .open           = afs_proc_servers_open,
124         .read           = seq_read,
125         .llseek         = seq_lseek,
126         .release        = seq_release,
127 };
128 
129 static int afs_proc_sysname_open(struct inode *inode, struct file *file);
130 static int afs_proc_sysname_release(struct inode *inode, struct file *file);
131 static void *afs_proc_sysname_start(struct seq_file *p, loff_t *pos);
132 static void *afs_proc_sysname_next(struct seq_file *p, void *v,
133                                         loff_t *pos);
134 static void afs_proc_sysname_stop(struct seq_file *p, void *v);
135 static int afs_proc_sysname_show(struct seq_file *m, void *v);
136 static ssize_t afs_proc_sysname_write(struct file *file,
137                                       const char __user *buf,
138                                       size_t size, loff_t *_pos);
139 
140 static const struct seq_operations afs_proc_sysname_ops = {
141         .start  = afs_proc_sysname_start,
142         .next   = afs_proc_sysname_next,
143         .stop   = afs_proc_sysname_stop,
144         .show   = afs_proc_sysname_show,
145 };
146 
147 static const struct file_operations afs_proc_sysname_fops = {
148         .open           = afs_proc_sysname_open,
149         .read           = seq_read,
150         .llseek         = seq_lseek,
151         .release        = afs_proc_sysname_release,
152         .write          = afs_proc_sysname_write,
153 };
154 
155 static const struct file_operations afs_proc_stats_fops;
156 
157 /*
158  * initialise the /proc/fs/afs/ directory
159  */
160 int afs_proc_init(struct afs_net *net)
161 {
162         _enter("");
163 
164         net->proc_afs = proc_mkdir("fs/afs", NULL);
165         if (!net->proc_afs)
166                 goto error_dir;
167 
168         if (!proc_create("cells", 0644, net->proc_afs, &afs_proc_cells_fops) ||
169             !proc_create("rootcell", 0644, net->proc_afs, &afs_proc_rootcell_fops) ||
170             !proc_create("servers", 0644, net->proc_afs, &afs_proc_servers_fops) ||
171             !proc_create("stats", 0644, net->proc_afs, &afs_proc_stats_fops) ||
172             !proc_create("sysname", 0644, net->proc_afs, &afs_proc_sysname_fops))
173                 goto error_tree;
174 
175         _leave(" = 0");
176         return 0;
177 
178 error_tree:
179         proc_remove(net->proc_afs);
180 error_dir:
181         _leave(" = -ENOMEM");
182         return -ENOMEM;
183 }
184 
185 /*
186  * clean up the /proc/fs/afs/ directory
187  */
188 void afs_proc_cleanup(struct afs_net *net)
189 {
190         proc_remove(net->proc_afs);
191         net->proc_afs = NULL;
192 }
193 
194 /*
195  * open "/proc/fs/afs/cells" which provides a summary of extant cells
196  */
197 static int afs_proc_cells_open(struct inode *inode, struct file *file)
198 {
199         struct seq_file *m;
200         int ret;
201 
202         ret = seq_open(file, &afs_proc_cells_ops);
203         if (ret < 0)
204                 return ret;
205 
206         m = file->private_data;
207         m->private = PDE_DATA(inode);
208         return 0;
209 }
210 
211 /*
212  * set up the iterator to start reading from the cells list and return the
213  * first item
214  */
215 static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
216         __acquires(rcu)
217 {
218         struct afs_net *net = afs_seq2net(m);
219 
220         rcu_read_lock();
221         return seq_list_start_head(&net->proc_cells, *_pos);
222 }
223 
224 /*
225  * move to next cell in cells list
226  */
227 static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos)
228 {
229         struct afs_net *net = afs_seq2net(m);
230 
231         return seq_list_next(v, &net->proc_cells, pos);
232 }
233 
234 /*
235  * clean up after reading from the cells list
236  */
237 static void afs_proc_cells_stop(struct seq_file *m, void *v)
238         __releases(rcu)
239 {
240         rcu_read_unlock();
241 }
242 
243 /*
244  * display a header line followed by a load of cell lines
245  */
246 static int afs_proc_cells_show(struct seq_file *m, void *v)
247 {
248         struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
249         struct afs_net *net = afs_seq2net(m);
250 
251         if (v == &net->proc_cells) {
252                 /* display header on line 1 */
253                 seq_puts(m, "USE NAME\n");
254                 return 0;
255         }
256 
257         /* display one cell per line on subsequent lines */
258         seq_printf(m, "%3u %s\n", atomic_read(&cell->usage), cell->name);
259         return 0;
260 }
261 
262 /*
263  * handle writes to /proc/fs/afs/cells
264  * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
265  */
266 static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
267                                     size_t size, loff_t *_pos)
268 {
269         struct afs_net *net = afs_proc2net(file);
270         char *kbuf, *name, *args;
271         int ret;
272 
273         /* start by dragging the command into memory */
274         if (size <= 1 || size >= PAGE_SIZE)
275                 return -EINVAL;
276 
277         kbuf = memdup_user_nul(buf, size);
278         if (IS_ERR(kbuf))
279                 return PTR_ERR(kbuf);
280 
281         /* trim to first NL */
282         name = memchr(kbuf, '\n', size);
283         if (name)
284                 *name = 0;
285 
286         /* split into command, name and argslist */
287         name = strchr(kbuf, ' ');
288         if (!name)
289                 goto inval;
290         do {
291                 *name++ = 0;
292         } while(*name == ' ');
293         if (!*name)
294                 goto inval;
295 
296         args = strchr(name, ' ');
297         if (!args)
298                 goto inval;
299         do {
300                 *args++ = 0;
301         } while(*args == ' ');
302         if (!*args)
303                 goto inval;
304 
305         /* determine command to perform */
306         _debug("cmd=%s name=%s args=%s", kbuf, name, args);
307 
308         if (strcmp(kbuf, "add") == 0) {
309                 struct afs_cell *cell;
310 
311                 cell = afs_lookup_cell(net, name, strlen(name), args, true);
312                 if (IS_ERR(cell)) {
313                         ret = PTR_ERR(cell);
314                         goto done;
315                 }
316 
317                 if (test_and_set_bit(AFS_CELL_FL_NO_GC, &cell->flags))
318                         afs_put_cell(net, cell);
319                 printk("kAFS: Added new cell '%s'\n", name);
320         } else {
321                 goto inval;
322         }
323 
324         ret = size;
325 
326 done:
327         kfree(kbuf);
328         _leave(" = %d", ret);
329         return ret;
330 
331 inval:
332         ret = -EINVAL;
333         printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
334         goto done;
335 }
336 
337 static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
338                                       size_t size, loff_t *_pos)
339 {
340         struct afs_cell *cell;
341         struct afs_net *net = afs_proc2net(file);
342         unsigned int seq = 0;
343         char name[AFS_MAXCELLNAME + 1];
344         int len;
345 
346         if (*_pos > 0)
347                 return 0;
348         if (!net->ws_cell)
349                 return 0;
350 
351         rcu_read_lock();
352         do {
353                 read_seqbegin_or_lock(&net->cells_lock, &seq);
354                 len = 0;
355                 cell = rcu_dereference_raw(net->ws_cell);
356                 if (cell) {
357                         len = cell->name_len;
358                         memcpy(name, cell->name, len);
359                 }
360         } while (need_seqretry(&net->cells_lock, seq));
361         done_seqretry(&net->cells_lock, seq);
362         rcu_read_unlock();
363 
364         if (!len)
365                 return 0;
366 
367         name[len++] = '\n';
368         if (len > size)
369                 len = size;
370         if (copy_to_user(buf, name, len) != 0)
371                 return -EFAULT;
372         *_pos = 1;
373         return len;
374 }
375 
376 /*
377  * handle writes to /proc/fs/afs/rootcell
378  * - to initialize rootcell: echo "cell.name:192.168.231.14"
379  */
380 static ssize_t afs_proc_rootcell_write(struct file *file,
381                                        const char __user *buf,
382                                        size_t size, loff_t *_pos)
383 {
384         struct afs_net *net = afs_proc2net(file);
385         char *kbuf, *s;
386         int ret;
387 
388         /* start by dragging the command into memory */
389         if (size <= 1 || size >= PAGE_SIZE)
390                 return -EINVAL;
391 
392         kbuf = memdup_user_nul(buf, size);
393         if (IS_ERR(kbuf))
394                 return PTR_ERR(kbuf);
395 
396         ret = -EINVAL;
397         if (kbuf[0] == '.')
398                 goto out;
399         if (memchr(kbuf, '/', size))
400                 goto out;
401 
402         /* trim to first NL */
403         s = memchr(kbuf, '\n', size);
404         if (s)
405                 *s = 0;
406 
407         /* determine command to perform */
408         _debug("rootcell=%s", kbuf);
409 
410         ret = afs_cell_init(net, kbuf);
411         if (ret >= 0)
412                 ret = size;     /* consume everything, always */
413 
414 out:
415         kfree(kbuf);
416         _leave(" = %d", ret);
417         return ret;
418 }
419 
420 /*
421  * initialise /proc/fs/afs/<cell>/
422  */
423 int afs_proc_cell_setup(struct afs_net *net, struct afs_cell *cell)
424 {
425         struct proc_dir_entry *dir;
426 
427         _enter("%p{%s},%p", cell, cell->name, net->proc_afs);
428 
429         dir = proc_mkdir(cell->name, net->proc_afs);
430         if (!dir)
431                 goto error_dir;
432 
433         if (!proc_create_data("vlservers", 0, dir,
434                               &afs_proc_cell_vlservers_fops, cell) ||
435             !proc_create_data("volumes", 0, dir,
436                               &afs_proc_cell_volumes_fops, cell))
437                 goto error_tree;
438 
439         _leave(" = 0");
440         return 0;
441 
442 error_tree:
443         remove_proc_subtree(cell->name, net->proc_afs);
444 error_dir:
445         _leave(" = -ENOMEM");
446         return -ENOMEM;
447 }
448 
449 /*
450  * remove /proc/fs/afs/<cell>/
451  */
452 void afs_proc_cell_remove(struct afs_net *net, struct afs_cell *cell)
453 {
454         _enter("");
455 
456         remove_proc_subtree(cell->name, net->proc_afs);
457 
458         _leave("");
459 }
460 
461 /*
462  * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells
463  */
464 static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file)
465 {
466         struct afs_cell *cell;
467         struct seq_file *m;
468         int ret;
469 
470         cell = PDE_DATA(inode);
471         if (!cell)
472                 return -ENOENT;
473 
474         ret = seq_open(file, &afs_proc_cell_volumes_ops);
475         if (ret < 0)
476                 return ret;
477 
478         m = file->private_data;
479         m->private = cell;
480 
481         return 0;
482 }
483 
484 /*
485  * set up the iterator to start reading from the cells list and return the
486  * first item
487  */
488 static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
489         __acquires(cell->proc_lock)
490 {
491         struct afs_cell *cell = m->private;
492 
493         _enter("cell=%p pos=%Ld", cell, *_pos);
494 
495         read_lock(&cell->proc_lock);
496         return seq_list_start_head(&cell->proc_volumes, *_pos);
497 }
498 
499 /*
500  * move to next cell in cells list
501  */
502 static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
503                                         loff_t *_pos)
504 {
505         struct afs_cell *cell = p->private;
506 
507         _enter("cell=%p pos=%Ld", cell, *_pos);
508         return seq_list_next(v, &cell->proc_volumes, _pos);
509 }
510 
511 /*
512  * clean up after reading from the cells list
513  */
514 static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v)
515         __releases(cell->proc_lock)
516 {
517         struct afs_cell *cell = p->private;
518 
519         read_unlock(&cell->proc_lock);
520 }
521 
522 static const char afs_vol_types[3][3] = {
523         [AFSVL_RWVOL]   = "RW",
524         [AFSVL_ROVOL]   = "RO",
525         [AFSVL_BACKVOL] = "BK",
526 };
527 
528 /*
529  * display a header line followed by a load of volume lines
530  */
531 static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
532 {
533         struct afs_cell *cell = m->private;
534         struct afs_volume *vol = list_entry(v, struct afs_volume, proc_link);
535 
536         /* Display header on line 1 */
537         if (v == &cell->proc_volumes) {
538                 seq_puts(m, "USE VID      TY\n");
539                 return 0;
540         }
541 
542         seq_printf(m, "%3d %08x %s\n",
543                    atomic_read(&vol->usage), vol->vid,
544                    afs_vol_types[vol->type]);
545 
546         return 0;
547 }
548 
549 /*
550  * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume
551  * location server
552  */
553 static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file)
554 {
555         struct afs_cell *cell;
556         struct seq_file *m;
557         int ret;
558 
559         cell = PDE_DATA(inode);
560         if (!cell)
561                 return -ENOENT;
562 
563         ret = seq_open(file, &afs_proc_cell_vlservers_ops);
564         if (ret<0)
565                 return ret;
566 
567         m = file->private_data;
568         m->private = cell;
569 
570         return 0;
571 }
572 
573 /*
574  * set up the iterator to start reading from the cells list and return the
575  * first item
576  */
577 static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
578         __acquires(rcu)
579 {
580         struct afs_addr_list *alist;
581         struct afs_cell *cell = m->private;
582         loff_t pos = *_pos;
583 
584         rcu_read_lock();
585 
586         alist = rcu_dereference(cell->vl_addrs);
587 
588         /* allow for the header line */
589         if (!pos)
590                 return (void *) 1;
591         pos--;
592 
593         if (!alist || pos >= alist->nr_addrs)
594                 return NULL;
595 
596         return alist->addrs + pos;
597 }
598 
599 /*
600  * move to next cell in cells list
601  */
602 static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
603                                           loff_t *_pos)
604 {
605         struct afs_addr_list *alist;
606         struct afs_cell *cell = p->private;
607         loff_t pos;
608 
609         alist = rcu_dereference(cell->vl_addrs);
610 
611         pos = *_pos;
612         (*_pos)++;
613         if (!alist || pos >= alist->nr_addrs)
614                 return NULL;
615 
616         return alist->addrs + pos;
617 }
618 
619 /*
620  * clean up after reading from the cells list
621  */
622 static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v)
623         __releases(rcu)
624 {
625         rcu_read_unlock();
626 }
627 
628 /*
629  * display a header line followed by a load of volume lines
630  */
631 static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
632 {
633         struct sockaddr_rxrpc *addr = v;
634 
635         /* display header on line 1 */
636         if (v == (void *)1) {
637                 seq_puts(m, "ADDRESS\n");
638                 return 0;
639         }
640 
641         /* display one cell per line on subsequent lines */
642         seq_printf(m, "%pISp\n", &addr->transport);
643         return 0;
644 }
645 
646 /*
647  * open "/proc/fs/afs/servers" which provides a summary of active
648  * servers
649  */
650 static int afs_proc_servers_open(struct inode *inode, struct file *file)
651 {
652         return seq_open(file, &afs_proc_servers_ops);
653 }
654 
655 /*
656  * Set up the iterator to start reading from the server list and return the
657  * first item.
658  */
659 static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos)
660         __acquires(rcu)
661 {
662         struct afs_net *net = afs_seq2net(m);
663 
664         rcu_read_lock();
665         return seq_hlist_start_head_rcu(&net->fs_proc, *_pos);
666 }
667 
668 /*
669  * move to next cell in cells list
670  */
671 static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos)
672 {
673         struct afs_net *net = afs_seq2net(m);
674 
675         return seq_hlist_next_rcu(v, &net->fs_proc, _pos);
676 }
677 
678 /*
679  * clean up after reading from the cells list
680  */
681 static void afs_proc_servers_stop(struct seq_file *p, void *v)
682         __releases(rcu)
683 {
684         rcu_read_unlock();
685 }
686 
687 /*
688  * display a header line followed by a load of volume lines
689  */
690 static int afs_proc_servers_show(struct seq_file *m, void *v)
691 {
692         struct afs_server *server;
693         struct afs_addr_list *alist;
694 
695         if (v == SEQ_START_TOKEN) {
696                 seq_puts(m, "UUID                                 USE ADDR\n");
697                 return 0;
698         }
699 
700         server = list_entry(v, struct afs_server, proc_link);
701         alist = rcu_dereference(server->addresses);
702         seq_printf(m, "%pU %3d %pISp\n",
703                    &server->uuid,
704                    atomic_read(&server->usage),
705                    &alist->addrs[alist->index].transport);
706         return 0;
707 }
708 
709 void afs_put_sysnames(struct afs_sysnames *sysnames)
710 {
711         int i;
712 
713         if (sysnames && refcount_dec_and_test(&sysnames->usage)) {
714                 for (i = 0; i < sysnames->nr; i++)
715                         if (sysnames->subs[i] != afs_init_sysname &&
716                             sysnames->subs[i] != sysnames->blank)
717                                 kfree(sysnames->subs[i]);
718         }
719 }
720 
721 /*
722  * Handle opening of /proc/fs/afs/sysname.  If it is opened for writing, we
723  * assume the caller wants to change the substitution list and we allocate a
724  * buffer to hold the list.
725  */
726 static int afs_proc_sysname_open(struct inode *inode, struct file *file)
727 {
728         struct afs_sysnames *sysnames;
729         struct seq_file *m;
730         int ret;
731 
732         ret = seq_open(file, &afs_proc_sysname_ops);
733         if (ret < 0)
734                 return ret;
735 
736         if (file->f_mode & FMODE_WRITE) {
737                 sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
738                 if (!sysnames) {
739                         seq_release(inode, file);
740                         return -ENOMEM;
741                 }
742 
743                 refcount_set(&sysnames->usage, 1);
744                 m = file->private_data;
745                 m->private = sysnames;
746         }
747 
748         return 0;
749 }
750 
751 /*
752  * Handle writes to /proc/fs/afs/sysname to set the @sys substitution.
753  */
754 static ssize_t afs_proc_sysname_write(struct file *file,
755                                       const char __user *buf,
756                                       size_t size, loff_t *_pos)
757 {
758         struct afs_sysnames *sysnames;
759         struct seq_file *m = file->private_data;
760         char *kbuf = NULL, *s, *p, *sub;
761         int ret, len;
762 
763         sysnames = m->private;
764         if (!sysnames)
765                 return -EINVAL;
766         if (sysnames->error)
767                 return sysnames->error;
768 
769         if (size >= PAGE_SIZE - 1) {
770                 sysnames->error = -EINVAL;
771                 return -EINVAL;
772         }
773         if (size == 0)
774                 return 0;
775 
776         kbuf = memdup_user_nul(buf, size);
777         if (IS_ERR(kbuf))
778                 return PTR_ERR(kbuf);
779 
780         inode_lock(file_inode(file));
781 
782         p = kbuf;
783         while ((s = strsep(&p, " \t\n"))) {
784                 len = strlen(s);
785                 if (len == 0)
786                         continue;
787                 ret = -ENAMETOOLONG;
788                 if (len >= AFSNAMEMAX)
789                         goto error;
790 
791                 if (len >= 4 &&
792                     s[len - 4] == '@' &&
793                     s[len - 3] == 's' &&
794                     s[len - 2] == 'y' &&
795                     s[len - 1] == 's')
796                         /* Protect against recursion */
797                         goto invalid;
798 
799                 if (s[0] == '.' &&
800                     (len < 2 || (len == 2 && s[1] == '.')))
801                         goto invalid;
802 
803                 if (memchr(s, '/', len))
804                         goto invalid;
805 
806                 ret = -EFBIG;
807                 if (sysnames->nr >= AFS_NR_SYSNAME)
808                         goto out;
809 
810                 if (strcmp(s, afs_init_sysname) == 0) {
811                         sub = (char *)afs_init_sysname;
812                 } else {
813                         ret = -ENOMEM;
814                         sub = kmemdup(s, len + 1, GFP_KERNEL);
815                         if (!sub)
816                                 goto out;
817                 }
818 
819                 sysnames->subs[sysnames->nr] = sub;
820                 sysnames->nr++;
821         }
822 
823         ret = size;     /* consume everything, always */
824 out:
825         inode_unlock(file_inode(file));
826         kfree(kbuf);
827         return ret;
828 
829 invalid:
830         ret = -EINVAL;
831 error:
832         sysnames->error = ret;
833         goto out;
834 }
835 
836 static int afs_proc_sysname_release(struct inode *inode, struct file *file)
837 {
838         struct afs_sysnames *sysnames, *kill = NULL;
839         struct seq_file *m = file->private_data;
840         struct afs_net *net = afs_seq2net(m);
841 
842         sysnames = m->private;
843         if (sysnames) {
844                 if (!sysnames->error) {
845                         kill = sysnames;
846                         if (sysnames->nr == 0) {
847                                 sysnames->subs[0] = sysnames->blank;
848                                 sysnames->nr++;
849                         }
850                         write_lock(&net->sysnames_lock);
851                         kill = net->sysnames;
852                         net->sysnames = sysnames;
853                         write_unlock(&net->sysnames_lock);
854                 }
855                 afs_put_sysnames(kill);
856         }
857 
858         return seq_release(inode, file);
859 }
860 
861 static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos)
862         __acquires(&net->sysnames_lock)
863 {
864         struct afs_net *net = afs_seq2net(m);
865         struct afs_sysnames *names = net->sysnames;
866 
867         read_lock(&net->sysnames_lock);
868 
869         if (*pos >= names->nr)
870                 return NULL;
871         return (void *)(unsigned long)(*pos + 1);
872 }
873 
874 static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos)
875 {
876         struct afs_net *net = afs_seq2net(m);
877         struct afs_sysnames *names = net->sysnames;
878 
879         *pos += 1;
880         if (*pos >= names->nr)
881                 return NULL;
882         return (void *)(unsigned long)(*pos + 1);
883 }
884 
885 static void afs_proc_sysname_stop(struct seq_file *m, void *v)
886         __releases(&net->sysnames_lock)
887 {
888         struct afs_net *net = afs_seq2net(m);
889 
890         read_unlock(&net->sysnames_lock);
891 }
892 
893 static int afs_proc_sysname_show(struct seq_file *m, void *v)
894 {
895         struct afs_net *net = afs_seq2net(m);
896         struct afs_sysnames *sysnames = net->sysnames;
897         unsigned int i = (unsigned long)v - 1;
898 
899         if (i < sysnames->nr)
900                 seq_printf(m, "%s\n", sysnames->subs[i]);
901         return 0;
902 }
903 
904 /*
905  * Display general per-net namespace statistics
906  */
907 static int afs_proc_stats_show(struct seq_file *m, void *v)
908 {
909         struct afs_net *net = afs_seq2net(m);
910 
911         seq_puts(m, "kAFS statistics\n");
912 
913         seq_printf(m, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n",
914                    atomic_read(&net->n_lookup),
915                    atomic_read(&net->n_reval),
916                    atomic_read(&net->n_inval),
917                    atomic_read(&net->n_relpg));
918 
919         seq_printf(m, "dir-data: rdpg=%u\n",
920                    atomic_read(&net->n_read_dir));
921 
922         seq_printf(m, "dir-edit: cr=%u rm=%u\n",
923                    atomic_read(&net->n_dir_cr),
924                    atomic_read(&net->n_dir_rm));
925 
926         seq_printf(m, "file-rd : n=%u nb=%lu\n",
927                    atomic_read(&net->n_fetches),
928                    atomic_long_read(&net->n_fetch_bytes));
929         seq_printf(m, "file-wr : n=%u nb=%lu\n",
930                    atomic_read(&net->n_stores),
931                    atomic_long_read(&net->n_store_bytes));
932         return 0;
933 }
934 
935 /*
936  * Open "/proc/fs/afs/stats" to allow reading of the stat counters.
937  */
938 static int afs_proc_stats_open(struct inode *inode, struct file *file)
939 {
940         return single_open(file, afs_proc_stats_show, NULL);
941 }
942 
943 static const struct file_operations afs_proc_stats_fops = {
944         .open           = afs_proc_stats_open,
945         .read           = seq_read,
946         .llseek         = seq_lseek,
947         .release        = single_release,
948 };
949 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp