2 * linux/kernel/vserver/proc.c
4 * Virtual Context Support
6 * Copyright (C) 2003-2005 Herbert Pƶtzl
8 * V0.01 basic structure
9 * V0.02 adaptation vs1.3.0
10 * V0.03 proc permissions
11 * V0.04 locking/generic
12 * V0.05 next generation procfs
13 * V0.06 inode validation
14 * V0.07 generic rewrite vid
18 #include <linux/config.h>
19 #include <linux/errno.h>
20 #include <linux/proc_fs.h>
21 #include <linux/sched.h>
22 #include <linux/vs_context.h>
23 #include <linux/vs_network.h>
24 #include <linux/vs_cvirt.h>
26 #include <linux/vserver/switch.h>
28 #include <asm/uaccess.h>
29 #include <asm/unistd.h>
31 #include "cvirt_proc.h"
32 #include "limit_proc.h"
33 #include "sched_proc.h"
34 #include "vci_config.h"
36 static struct proc_dir_entry *proc_virtual;
38 static struct proc_dir_entry *proc_vnet;
41 enum vid_directory_inos {
55 #define PROC_VID_MASK 0x60
58 /* first the actual feeds */
61 static int proc_virtual_info(int vid, char *buffer)
63 return sprintf(buffer,
64 "VCIVersion:\t%04x:%04x\n"
75 int proc_xid_info (int vid, char *buffer)
80 vxi = locate_vx_info(vid);
83 length = sprintf(buffer,
95 int proc_xid_status (int vid, char *buffer)
100 vxi = locate_vx_info(vid);
103 length = sprintf(buffer,
110 ,atomic_read(&vxi->vx_usecnt)
111 ,atomic_read(&vxi->vx_tasks)
112 ,(unsigned long long)vxi->vx_flags
113 ,(unsigned long long)vxi->vx_bcaps
114 ,(unsigned long long)vxi->vx_ccaps
115 ,atomic_read(&vxi->limit.ticks)
121 int proc_xid_limit (int vid, char *buffer)
126 vxi = locate_vx_info(vid);
129 length = vx_info_proc_limit(&vxi->limit, buffer);
134 int proc_xid_sched (int vid, char *buffer)
139 vxi = locate_vx_info(vid);
142 length = vx_info_proc_sched(&vxi->sched, buffer);
147 int proc_xid_cvirt (int vid, char *buffer)
152 vxi = locate_vx_info(vid);
156 length = vx_info_proc_cvirt(&vxi->cvirt, buffer);
161 int proc_xid_cacct (int vid, char *buffer)
166 vxi = locate_vx_info(vid);
169 length = vx_info_proc_cacct(&vxi->cacct, buffer);
175 static int proc_vnet_info(int vid, char *buffer)
177 return sprintf(buffer,
178 "VCIVersion:\t%04x:%04x\n"
181 ,VCI_VERSION & 0xFFFF
187 (((a)>>0) & 0xff), (((a)>>8) & 0xff), \
188 (((a)>>16) & 0xff), (((a)>>24) & 0xff)
190 int proc_nid_info (int vid, char *buffer)
195 nxi = locate_nx_info(vid);
198 length = sprintf(buffer,
204 for (i=0; i<nxi->nbipv4; i++) {
205 length += sprintf(buffer + length,
206 "%d:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i,
207 atoquad(nxi->ipv4[i]),
208 atoquad(nxi->mask[i]));
214 int proc_nid_status (int vid, char *buffer)
219 nxi = locate_nx_info(vid);
222 length = sprintf(buffer,
225 ,atomic_read(&nxi->nx_usecnt)
226 ,atomic_read(&nxi->nx_tasks)
232 /* here the inode helpers */
235 #define fake_ino(id,nr) (((nr) & 0xFFFF) | \
236 (((id) & 0xFFFF) << 16))
238 #define inode_vid(i) (((i)->i_ino >> 16) & 0xFFFF)
239 #define inode_type(i) ((i)->i_ino & 0xFFFF)
241 #define MAX_MULBY10 ((~0U-9)/10)
244 static struct inode *proc_vid_make_inode(struct super_block * sb,
247 struct inode *inode = new_inode(sb);
252 inode->i_mtime = inode->i_atime =
253 inode->i_ctime = CURRENT_TIME;
254 inode->i_ino = fake_ino(vid, ino);
262 static int proc_vid_revalidate(struct dentry * dentry, struct nameidata *nd)
264 struct inode * inode = dentry->d_inode;
267 vid = inode_vid(inode);
268 switch (inode_type(inode) & PROC_VID_MASK) {
270 hashed = xid_is_hashed(vid);
273 hashed = nid_is_hashed(vid);
283 #define PROC_BLOCK_SIZE (PAGE_SIZE - 1024)
285 static ssize_t proc_vid_info_read(struct file * file, char * buf,
286 size_t count, loff_t *ppos)
288 struct inode * inode = file->f_dentry->d_inode;
293 if (count > PROC_BLOCK_SIZE)
294 count = PROC_BLOCK_SIZE;
295 if (!(page = __get_free_page(GFP_KERNEL)))
298 vid = inode_vid(inode);
299 length = PROC_I(inode)->op.proc_vid_read(vid, (char*)page);
302 length = simple_read_from_buffer(buf, count, ppos,
303 (char *)page, length);
312 /* here comes the lower level (vid) */
314 static struct file_operations proc_vid_info_file_operations = {
315 read: proc_vid_info_read,
318 static struct dentry_operations proc_vid_dentry_operations = {
319 d_revalidate: proc_vid_revalidate,
330 #define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
332 static struct vid_entry vx_base_stuff[] = {
333 E(PROC_XID_INFO, "info", S_IFREG|S_IRUGO),
334 E(PROC_XID_STATUS, "status", S_IFREG|S_IRUGO),
335 E(PROC_XID_LIMIT, "limit", S_IFREG|S_IRUGO),
336 E(PROC_XID_SCHED, "sched", S_IFREG|S_IRUGO),
337 E(PROC_XID_CVIRT, "cvirt", S_IFREG|S_IRUGO),
338 E(PROC_XID_CACCT, "cacct", S_IFREG|S_IRUGO),
342 static struct vid_entry vn_base_stuff[] = {
343 E(PROC_NID_INFO, "info", S_IFREG|S_IRUGO),
344 E(PROC_NID_STATUS, "status", S_IFREG|S_IRUGO),
350 static struct dentry *proc_vid_lookup(struct inode *dir,
351 struct dentry *dentry, struct nameidata *nd)
360 switch (inode_type(dir)) {
371 for (; p->name; p++) {
372 if (p->len != dentry->d_name.len)
374 if (!memcmp(dentry->d_name.name, p->name, p->len))
381 inode = proc_vid_make_inode(dir->i_sb, inode_vid(dir), p->type);
387 PROC_I(inode)->op.proc_vid_read = proc_xid_info;
389 case PROC_XID_STATUS:
390 PROC_I(inode)->op.proc_vid_read = proc_xid_status;
393 PROC_I(inode)->op.proc_vid_read = proc_xid_limit;
396 PROC_I(inode)->op.proc_vid_read = proc_xid_sched;
399 PROC_I(inode)->op.proc_vid_read = proc_xid_cvirt;
402 PROC_I(inode)->op.proc_vid_read = proc_xid_cacct;
406 PROC_I(inode)->op.proc_vid_read = proc_nid_info;
408 case PROC_NID_STATUS:
409 PROC_I(inode)->op.proc_vid_read = proc_nid_status;
413 printk("procfs: impossible type (%d)",p->type);
415 return ERR_PTR(-EINVAL);
417 inode->i_mode = p->mode;
418 inode->i_fop = &proc_vid_info_file_operations;
420 inode->i_flags|=S_IMMUTABLE;
422 dentry->d_op = &proc_vid_dentry_operations;
423 d_add(dentry, inode);
426 return ERR_PTR(error);
430 static int proc_vid_readdir(struct file * filp,
431 void * dirent, filldir_t filldir)
434 struct inode *inode = filp->f_dentry->d_inode;
440 if (filldir(dirent, ".", 1, i,
441 inode->i_ino, DT_DIR) < 0)
447 if (filldir(dirent, "..", 2, i,
448 PROC_ROOT_INO, DT_DIR) < 0)
455 switch (inode_type(inode)) {
457 size = sizeof(vx_base_stuff);
458 p = vx_base_stuff + i;
461 size = sizeof(vn_base_stuff);
462 p = vn_base_stuff + i;
467 if (i >= size/sizeof(struct vid_entry))
470 if (filldir(dirent, p->name, p->len,
471 filp->f_pos, fake_ino(inode_vid(inode),
472 p->type), p->mode >> 12) < 0)
484 /* now the upper level (virtual) */
486 static struct file_operations proc_vid_file_operations = {
487 read: generic_read_dir,
488 readdir: proc_vid_readdir,
491 static struct inode_operations proc_vid_inode_operations = {
492 lookup: proc_vid_lookup,
497 static __inline__ int atovid(const char *str, int len)
507 if (vid >= MAX_MULBY10)
518 struct dentry *proc_virtual_lookup(struct inode *dir,
519 struct dentry * dentry, struct nameidata *nd)
526 name = dentry->d_name.name;
527 len = dentry->d_name.len;
530 if (len == 7 && !memcmp(name, "current", 7)) {
531 inode = new_inode(dir->i_sb);
534 inode->i_mtime = inode->i_atime =
535 inode->i_ctime = CURRENT_TIME;
536 inode->i_ino = fake_ino(1, PROC_XID_INO);
537 inode->i_mode = S_IFLNK|S_IRWXUGO;
538 inode->i_uid = inode->i_gid = 0;
539 d_add(dentry, inode);
542 if (len == 4 && !memcmp(name, "info", 4)) {
543 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_XID_INFO);
546 inode->i_fop = &proc_vid_info_file_operations;
547 PROC_I(inode)->op.proc_vid_read = proc_virtual_info;
548 inode->i_mode = S_IFREG|S_IRUGO;
549 d_add(dentry, inode);
554 xid = atovid(name, len);
557 vxi = locate_vx_info(xid);
562 if (vx_check(xid, VX_ADMIN|VX_WATCH|VX_IDENT))
563 inode = proc_vid_make_inode(dir->i_sb,
564 vxi->vx_id, PROC_XID_INO);
568 inode->i_mode = S_IFDIR|S_IRUGO;
569 inode->i_op = &proc_vid_inode_operations;
570 inode->i_fop = &proc_vid_file_operations;
572 inode->i_flags|=S_IMMUTABLE;
574 dentry->d_op = &proc_vid_dentry_operations;
575 d_add(dentry, inode);
585 struct dentry *proc_vnet_lookup(struct inode *dir,
586 struct dentry * dentry, struct nameidata *nd)
593 name = dentry->d_name.name;
594 len = dentry->d_name.len;
596 if (len == 7 && !memcmp(name, "current", 7)) {
597 inode = new_inode(dir->i_sb);
600 inode->i_mtime = inode->i_atime =
601 inode->i_ctime = CURRENT_TIME;
602 inode->i_ino = fake_ino(1, PROC_NID_INO);
603 inode->i_mode = S_IFLNK|S_IRWXUGO;
604 inode->i_uid = inode->i_gid = 0;
605 d_add(dentry, inode);
608 if (len == 4 && !memcmp(name, "info", 4)) {
609 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_NID_INFO);
612 inode->i_fop = &proc_vid_info_file_operations;
613 PROC_I(inode)->op.proc_vid_read = proc_vnet_info;
614 inode->i_mode = S_IFREG|S_IRUGO;
615 d_add(dentry, inode);
620 nid = atovid(name, len);
623 nxi = locate_nx_info(nid);
629 inode = proc_vid_make_inode(dir->i_sb,
630 nxi->nx_id, PROC_NID_INO);
634 inode->i_mode = S_IFDIR|S_IRUGO;
635 inode->i_op = &proc_vid_inode_operations;
636 inode->i_fop = &proc_vid_file_operations;
638 inode->i_flags|=S_IMMUTABLE;
640 dentry->d_op = &proc_vid_dentry_operations;
641 d_add(dentry, inode);
653 #define PROC_NUMBUF 10
654 #define PROC_MAXVIDS 32
656 int proc_virtual_readdir(struct file * filp,
657 void * dirent, filldir_t filldir)
659 unsigned int xid_array[PROC_MAXVIDS];
660 char buf[PROC_NUMBUF];
661 unsigned int nr = filp->f_pos-3;
662 unsigned int nr_xids, i;
665 switch ((long)filp->f_pos) {
667 ino = fake_ino(0, PROC_XID_INO);
668 if (filldir(dirent, ".", 1,
669 filp->f_pos, ino, DT_DIR) < 0)
674 ino = filp->f_dentry->d_parent->d_inode->i_ino;
675 if (filldir(dirent, "..", 2,
676 filp->f_pos, ino, DT_DIR) < 0)
681 ino = fake_ino(0, PROC_XID_INFO);
682 if (filldir(dirent, "info", 4,
683 filp->f_pos, ino, DT_LNK) < 0)
688 if (vx_current_xid() > 1) {
689 ino = fake_ino(1, PROC_XID_INO);
690 if (filldir(dirent, "current", 7,
691 filp->f_pos, ino, DT_LNK) < 0)
697 nr_xids = get_xid_list(nr, xid_array, PROC_MAXVIDS);
698 for (i = 0; i < nr_xids; i++) {
699 int xid = xid_array[i];
700 ino_t ino = fake_ino(xid, PROC_XID_INO);
701 unsigned int j = PROC_NUMBUF;
703 do buf[--j] = '0' + (xid % 10); while (xid/=10);
705 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
706 filp->f_pos, ino, DT_DIR) < 0)
714 static struct file_operations proc_virtual_dir_operations = {
715 read: generic_read_dir,
716 readdir: proc_virtual_readdir,
719 static struct inode_operations proc_virtual_dir_inode_operations = {
720 lookup: proc_virtual_lookup,
724 int proc_vnet_readdir(struct file * filp,
725 void * dirent, filldir_t filldir)
727 unsigned int nid_array[PROC_MAXVIDS];
728 char buf[PROC_NUMBUF];
729 unsigned int nr = filp->f_pos-3;
730 unsigned int nr_nids, i;
733 switch ((long)filp->f_pos) {
735 ino = fake_ino(0, PROC_NID_INO);
736 if (filldir(dirent, ".", 1,
737 filp->f_pos, ino, DT_DIR) < 0)
742 ino = filp->f_dentry->d_parent->d_inode->i_ino;
743 if (filldir(dirent, "..", 2,
744 filp->f_pos, ino, DT_DIR) < 0)
749 ino = fake_ino(0, PROC_NID_INFO);
750 if (filldir(dirent, "info", 4,
751 filp->f_pos, ino, DT_LNK) < 0)
756 if (vx_current_xid() > 1) {
757 ino = fake_ino(1, PROC_NID_INO);
758 if (filldir(dirent, "current", 7,
759 filp->f_pos, ino, DT_LNK) < 0)
765 nr_nids = get_nid_list(nr, nid_array, PROC_MAXVIDS);
766 for (i = 0; i < nr_nids; i++) {
767 int nid = nid_array[i];
768 ino_t ino = fake_ino(nid, PROC_NID_INO);
769 unsigned long j = PROC_NUMBUF;
771 do buf[--j] = '0' + (nid % 10); while (nid/=10);
773 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
774 filp->f_pos, ino, DT_DIR) < 0)
782 static struct file_operations proc_vnet_dir_operations = {
783 read: generic_read_dir,
784 readdir: proc_vnet_readdir,
787 static struct inode_operations proc_vnet_dir_inode_operations = {
788 lookup: proc_vnet_lookup,
793 void proc_vx_init(void)
795 struct proc_dir_entry *ent;
797 ent = proc_mkdir("virtual", 0);
799 ent->proc_fops = &proc_virtual_dir_operations;
800 ent->proc_iops = &proc_virtual_dir_inode_operations;
804 ent = proc_mkdir("virtnet", 0);
806 ent->proc_fops = &proc_vnet_dir_operations;
807 ent->proc_iops = &proc_vnet_dir_inode_operations;
818 int proc_pid_vx_info(struct task_struct *p, char *buffer)
821 char * orig = buffer;
823 buffer += sprintf (buffer,"XID:\t%d\n", vx_task_xid(p));
824 vxi = task_get_vx_info(p);
825 if (vxi && !vx_flags(VXF_INFO_HIDE, 0)) {
826 buffer += sprintf (buffer,"BCaps:\t%016llx\n"
827 ,(unsigned long long)vxi->vx_bcaps);
828 buffer += sprintf (buffer,"CCaps:\t%016llx\n"
829 ,(unsigned long long)vxi->vx_ccaps);
830 buffer += sprintf (buffer,"CFlags:\t%016llx\n"
831 ,(unsigned long long)vxi->vx_flags);
832 buffer += sprintf (buffer,"CIPid:\t%d\n"
836 return buffer - orig;
840 int proc_pid_nx_info(struct task_struct *p, char *buffer)
843 char * orig = buffer;
845 buffer += sprintf (buffer,"NID:\t%d\n", nx_task_nid(p));
846 nxi = task_get_nx_info(p);
847 if (nxi && !vx_flags(VXF_INFO_HIDE, 0)) {
850 for (i=0; i<nxi->nbipv4; i++){
851 buffer += sprintf (buffer,
852 "V4Root[%d]:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i
853 ,NIPQUAD(nxi->ipv4[i])
854 ,NIPQUAD(nxi->mask[i]));
856 buffer += sprintf (buffer,
857 "V4Root[bcast]:\t%d.%d.%d.%d\n"
858 ,NIPQUAD(nxi->v4_bcast));
861 return buffer - orig;