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 */ | ||
