aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipc/util.c156
-rw-r--r--ipc/util.h8
2 files changed, 164 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
34struct 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
99static 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 */
108void __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
629static 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 */
658static 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
688static 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
701static 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
711static 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
718static 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
730static 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 */
diff --git a/ipc/util.h b/ipc/util.h
index 44348ca5a707..fc9a28be0797 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -30,7 +30,15 @@ struct ipc_ids {
30 struct ipc_id_ary* entries; 30 struct ipc_id_ary* entries;
31}; 31};
32 32
33struct seq_file;
33void __init ipc_init_ids(struct ipc_ids* ids, int size); 34void __init ipc_init_ids(struct ipc_ids* ids, int size);
35#ifdef CONFIG_PROC_FS
36void __init ipc_init_proc_interface(const char *path, const char *header,
37 struct ipc_ids *ids,
38 int (*show)(struct seq_file *, void *));
39#else
40#define ipc_init_proc_interface(path, header, ids, show) do {} while (0)
41#endif
34 42
35/* must be called with ids->sem acquired.*/ 43/* must be called with ids->sem acquired.*/
36int ipc_findkey(struct ipc_ids* ids, key_t key); 44int ipc_findkey(struct ipc_ids* ids, key_t key);