diff options
Diffstat (limited to 'ipc/util.c')
-rw-r--r-- | ipc/util.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/ipc/util.c b/ipc/util.c index e00c35f7b2b8..10e836d0d89e 100644 --- a/ipc/util.c +++ b/ipc/util.c | |||
@@ -24,11 +24,20 @@ | |||
24 | #include <linux/security.h> | 24 | #include <linux/security.h> |
25 | #include <linux/rcupdate.h> | 25 | #include <linux/rcupdate.h> |
26 | #include <linux/workqueue.h> | 26 | #include <linux/workqueue.h> |
27 | #include <linux/seq_file.h> | ||
28 | #include <linux/proc_fs.h> | ||
27 | 29 | ||
28 | #include <asm/unistd.h> | 30 | #include <asm/unistd.h> |
29 | 31 | ||
30 | #include "util.h" | 32 | #include "util.h" |
31 | 33 | ||
34 | struct ipc_proc_iface { | ||
35 | const char *path; | ||
36 | const char *header; | ||
37 | struct ipc_ids *ids; | ||
38 | int (*show)(struct seq_file *, void *); | ||
39 | }; | ||
40 | |||
32 | /** | 41 | /** |
33 | * ipc_init - initialise IPC subsystem | 42 | * ipc_init - initialise IPC subsystem |
34 | * | 43 | * |
@@ -86,6 +95,43 @@ void __init ipc_init_ids(struct ipc_ids* ids, int size) | |||
86 | ids->entries->p[i] = NULL; | 95 | ids->entries->p[i] = NULL; |
87 | } | 96 | } |
88 | 97 | ||
98 | #ifdef CONFIG_PROC_FS | ||
99 | static struct file_operations sysvipc_proc_fops; | ||
100 | /** | ||
101 | * ipc_init_proc_interface - Create a proc interface for sysipc types | ||
102 | * using a seq_file interface. | ||
103 | * @path: Path in procfs | ||
104 | * @header: Banner to be printed at the beginning of the file. | ||
105 | * @ids: ipc id table to iterate. | ||
106 | * @show: show routine. | ||
107 | */ | ||
108 | void __init ipc_init_proc_interface(const char *path, const char *header, | ||
109 | struct ipc_ids *ids, | ||
110 | int (*show)(struct seq_file *, void *)) | ||
111 | { | ||
112 | struct proc_dir_entry *pde; | ||
113 | struct ipc_proc_iface *iface; | ||
114 | |||
115 | iface = kmalloc(sizeof(*iface), GFP_KERNEL); | ||
116 | if (!iface) | ||
117 | return; | ||
118 | iface->path = path; | ||
119 | iface->header = header; | ||
120 | iface->ids = ids; | ||
121 | iface->show = show; | ||
122 | |||
123 | pde = create_proc_entry(path, | ||
124 | S_IRUGO, /* world readable */ | ||
125 | NULL /* parent dir */); | ||
126 | if (pde) { | ||
127 | pde->data = iface; | ||
128 | pde->proc_fops = &sysvipc_proc_fops; | ||
129 | } else { | ||
130 | kfree(iface); | ||
131 | } | ||
132 | } | ||
133 | #endif | ||
134 | |||
89 | /** | 135 | /** |
90 | * ipc_findkey - find a key in an ipc identifier set | 136 | * ipc_findkey - find a key in an ipc identifier set |
91 | * @ids: Identifier set | 137 | * @ids: Identifier set |
@@ -578,3 +624,113 @@ int ipc_parse_version (int *cmd) | |||
578 | } | 624 | } |
579 | 625 | ||
580 | #endif /* __ARCH_WANT_IPC_PARSE_VERSION */ | 626 | #endif /* __ARCH_WANT_IPC_PARSE_VERSION */ |
627 | |||
628 | #ifdef CONFIG_PROC_FS | ||
629 | static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos) | ||
630 | { | ||
631 | struct ipc_proc_iface *iface = s->private; | ||
632 | struct kern_ipc_perm *ipc = it; | ||
633 | loff_t p; | ||
634 | |||
635 | /* If we had an ipc id locked before, unlock it */ | ||
636 | if (ipc && ipc != SEQ_START_TOKEN) | ||
637 | ipc_unlock(ipc); | ||
638 | |||
639 | /* | ||
640 | * p = *pos - 1 (because id 0 starts at position 1) | ||
641 | * + 1 (because we increment the position by one) | ||
642 | */ | ||
643 | for (p = *pos; p <= iface->ids->max_id; p++) { | ||
644 | if ((ipc = ipc_lock(iface->ids, p)) != NULL) { | ||
645 | *pos = p + 1; | ||
646 | return ipc; | ||
647 | } | ||
648 | } | ||
649 | |||
650 | /* Out of range - return NULL to terminate iteration */ | ||
651 | return NULL; | ||
652 | } | ||
653 | |||
654 | /* | ||
655 | * File positions: pos 0 -> header, pos n -> ipc id + 1. | ||
656 | * SeqFile iterator: iterator value locked shp or SEQ_TOKEN_START. | ||
657 | */ | ||
658 | static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) | ||
659 | { | ||
660 | struct ipc_proc_iface *iface = s->private; | ||
661 | struct kern_ipc_perm *ipc; | ||
662 | loff_t p; | ||
663 | |||
664 | /* | ||
665 | * Take the lock - this will be released by the corresponding | ||
666 | * call to stop(). | ||
667 | */ | ||
668 | down(&iface->ids->sem); | ||
669 | |||
670 | /* pos < 0 is invalid */ | ||
671 | if (*pos < 0) | ||
672 | return NULL; | ||
673 | |||
674 | /* pos == 0 means header */ | ||
675 | if (*pos == 0) | ||
676 | return SEQ_START_TOKEN; | ||
677 | |||
678 | /* Find the (pos-1)th ipc */ | ||
679 | for (p = *pos - 1; p <= iface->ids->max_id; p++) { | ||
680 | if ((ipc = ipc_lock(iface->ids, p)) != NULL) { | ||
681 | *pos = p + 1; | ||
682 | return ipc; | ||
683 | } | ||
684 | } | ||
685 | return NULL; | ||
686 | } | ||
687 | |||
688 | static void sysvipc_proc_stop(struct seq_file *s, void *it) | ||
689 | { | ||
690 | struct kern_ipc_perm *ipc = it; | ||
691 | struct ipc_proc_iface *iface = s->private; | ||
692 | |||
693 | /* If we had a locked segment, release it */ | ||
694 | if (ipc && ipc != SEQ_START_TOKEN) | ||
695 | ipc_unlock(ipc); | ||
696 | |||
697 | /* Release the lock we took in start() */ | ||
698 | up(&iface->ids->sem); | ||
699 | } | ||
700 | |||
701 | static int sysvipc_proc_show(struct seq_file *s, void *it) | ||
702 | { | ||
703 | struct ipc_proc_iface *iface = s->private; | ||
704 | |||
705 | if (it == SEQ_START_TOKEN) | ||
706 | return seq_puts(s, iface->header); | ||
707 | |||
708 | return iface->show(s, it); | ||
709 | } | ||
710 | |||
711 | static struct seq_operations sysvipc_proc_seqops = { | ||
712 | .start = sysvipc_proc_start, | ||
713 | .stop = sysvipc_proc_stop, | ||
714 | .next = sysvipc_proc_next, | ||
715 | .show = sysvipc_proc_show, | ||
716 | }; | ||
717 | |||
718 | static int sysvipc_proc_open(struct inode *inode, struct file *file) { | ||
719 | int ret; | ||
720 | struct seq_file *seq; | ||
721 | |||
722 | ret = seq_open(file, &sysvipc_proc_seqops); | ||
723 | if (!ret) { | ||
724 | seq = file->private_data; | ||
725 | seq->private = PDE(inode)->data; | ||
726 | } | ||
727 | return ret; | ||
728 | } | ||
729 | |||
730 | static struct file_operations sysvipc_proc_fops = { | ||
731 | .open = sysvipc_proc_open, | ||
732 | .read = seq_read, | ||
733 | .llseek = seq_lseek, | ||
734 | .release = seq_release, | ||
735 | }; | ||
736 | #endif /* CONFIG_PROC_FS */ | ||