Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] ipc: add generic struct ipc_ids seq_file iteration

The following two patches convert /proc/sysvipc/* to use seq_file.

This gives us the following:

- Self-consistent IPC records in proc.
- O(n) reading of the files themselves.

This patch:

Add a generic method for ipc types to be displayed using seq_file. This
patch abstracts out seq_file iterating over struct ipc_ids into ipc/util.c

Signed-off-by: Mike Waychison <mikew@google.com>
Cc: Manfred Spraul <manfred@colorfullife.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Mike Waychison and committed by
Linus Torvalds
ae781774 f35279d3

+164
+156
ipc/util.c
··· 24 24 #include <linux/security.h> 25 25 #include <linux/rcupdate.h> 26 26 #include <linux/workqueue.h> 27 + #include <linux/seq_file.h> 28 + #include <linux/proc_fs.h> 27 29 28 30 #include <asm/unistd.h> 29 31 30 32 #include "util.h" 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 + }; 31 40 32 41 /** 33 42 * ipc_init - initialise IPC subsystem ··· 94 85 for(i=0;i<size;i++) 95 86 ids->entries->p[i] = NULL; 96 87 } 88 + 89 + #ifdef CONFIG_PROC_FS 90 + static struct file_operations sysvipc_proc_fops; 91 + /** 92 + * ipc_init_proc_interface - Create a proc interface for sysipc types 93 + * using a seq_file interface. 94 + * @path: Path in procfs 95 + * @header: Banner to be printed at the beginning of the file. 96 + * @ids: ipc id table to iterate. 97 + * @show: show routine. 98 + */ 99 + void __init ipc_init_proc_interface(const char *path, const char *header, 100 + struct ipc_ids *ids, 101 + int (*show)(struct seq_file *, void *)) 102 + { 103 + struct proc_dir_entry *pde; 104 + struct ipc_proc_iface *iface; 105 + 106 + iface = kmalloc(sizeof(*iface), GFP_KERNEL); 107 + if (!iface) 108 + return; 109 + iface->path = path; 110 + iface->header = header; 111 + iface->ids = ids; 112 + iface->show = show; 113 + 114 + pde = create_proc_entry(path, 115 + S_IRUGO, /* world readable */ 116 + NULL /* parent dir */); 117 + if (pde) { 118 + pde->data = iface; 119 + pde->proc_fops = &sysvipc_proc_fops; 120 + } else { 121 + kfree(iface); 122 + } 123 + } 124 + #endif 97 125 98 126 /** 99 127 * ipc_findkey - find a key in an ipc identifier set ··· 624 578 } 625 579 626 580 #endif /* __ARCH_WANT_IPC_PARSE_VERSION */ 581 + 582 + #ifdef CONFIG_PROC_FS 583 + static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos) 584 + { 585 + struct ipc_proc_iface *iface = s->private; 586 + struct kern_ipc_perm *ipc = it; 587 + loff_t p; 588 + 589 + /* If we had an ipc id locked before, unlock it */ 590 + if (ipc && ipc != SEQ_START_TOKEN) 591 + ipc_unlock(ipc); 592 + 593 + /* 594 + * p = *pos - 1 (because id 0 starts at position 1) 595 + * + 1 (because we increment the position by one) 596 + */ 597 + for (p = *pos; p <= iface->ids->max_id; p++) { 598 + if ((ipc = ipc_lock(iface->ids, p)) != NULL) { 599 + *pos = p + 1; 600 + return ipc; 601 + } 602 + } 603 + 604 + /* Out of range - return NULL to terminate iteration */ 605 + return NULL; 606 + } 607 + 608 + /* 609 + * File positions: pos 0 -> header, pos n -> ipc id + 1. 610 + * SeqFile iterator: iterator value locked shp or SEQ_TOKEN_START. 611 + */ 612 + static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) 613 + { 614 + struct ipc_proc_iface *iface = s->private; 615 + struct kern_ipc_perm *ipc; 616 + loff_t p; 617 + 618 + /* 619 + * Take the lock - this will be released by the corresponding 620 + * call to stop(). 621 + */ 622 + down(&iface->ids->sem); 623 + 624 + /* pos < 0 is invalid */ 625 + if (*pos < 0) 626 + return NULL; 627 + 628 + /* pos == 0 means header */ 629 + if (*pos == 0) 630 + return SEQ_START_TOKEN; 631 + 632 + /* Find the (pos-1)th ipc */ 633 + for (p = *pos - 1; p <= iface->ids->max_id; p++) { 634 + if ((ipc = ipc_lock(iface->ids, p)) != NULL) { 635 + *pos = p + 1; 636 + return ipc; 637 + } 638 + } 639 + return NULL; 640 + } 641 + 642 + static void sysvipc_proc_stop(struct seq_file *s, void *it) 643 + { 644 + struct kern_ipc_perm *ipc = it; 645 + struct ipc_proc_iface *iface = s->private; 646 + 647 + /* If we had a locked segment, release it */ 648 + if (ipc && ipc != SEQ_START_TOKEN) 649 + ipc_unlock(ipc); 650 + 651 + /* Release the lock we took in start() */ 652 + up(&iface->ids->sem); 653 + } 654 + 655 + static int sysvipc_proc_show(struct seq_file *s, void *it) 656 + { 657 + struct ipc_proc_iface *iface = s->private; 658 + 659 + if (it == SEQ_START_TOKEN) 660 + return seq_puts(s, iface->header); 661 + 662 + return iface->show(s, it); 663 + } 664 + 665 + static struct seq_operations sysvipc_proc_seqops = { 666 + .start = sysvipc_proc_start, 667 + .stop = sysvipc_proc_stop, 668 + .next = sysvipc_proc_next, 669 + .show = sysvipc_proc_show, 670 + }; 671 + 672 + static int sysvipc_proc_open(struct inode *inode, struct file *file) { 673 + int ret; 674 + struct seq_file *seq; 675 + 676 + ret = seq_open(file, &sysvipc_proc_seqops); 677 + if (!ret) { 678 + seq = file->private_data; 679 + seq->private = PDE(inode)->data; 680 + } 681 + return ret; 682 + } 683 + 684 + static struct file_operations sysvipc_proc_fops = { 685 + .open = sysvipc_proc_open, 686 + .read = seq_read, 687 + .llseek = seq_lseek, 688 + .release = seq_release, 689 + }; 690 + #endif /* CONFIG_PROC_FS */
+8
ipc/util.h
··· 30 30 struct ipc_id_ary* entries; 31 31 }; 32 32 33 + struct seq_file; 33 34 void __init ipc_init_ids(struct ipc_ids* ids, int size); 35 + #ifdef CONFIG_PROC_FS 36 + void __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 43 /* must be called with ids->sem acquired.*/ 36 44 int ipc_findkey(struct ipc_ids* ids, key_t key);