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/errno.h>
19 #include <linux/proc_fs.h>
20 #include <linux/sched.h>
21 #include <linux/vs_base.h>
22 #include <linux/vs_context.h>
23 #include <linux/vs_network.h>
24 #include <linux/vs_cvirt.h>
25 #include <linux/vserver/switch.h>
27 #include <asm/uaccess.h>
28 #include <asm/unistd.h>
30 #include "cvirt_proc.h"
31 #include "limit_proc.h"
32 #include "sched_proc.h"
33 #include "vci_config.h"
35 static struct proc_dir_entry *proc_virtual;
37 static struct proc_dir_entry *proc_vnet;
40 enum vid_directory_inos {
54 #define PROC_VID_MASK 0x60
57 /* first the actual feeds */
60 static int proc_virtual_info(int vid, char *buffer)
62 return sprintf(buffer,
63 "VCIVersion:\t%04x:%04x\n"
74 int proc_xid_info (int vid, char *buffer)
79 vxi = lookup_vx_info(vid);
82 length = sprintf(buffer,
94 int proc_xid_status (int vid, char *buffer)
99 vxi = lookup_vx_info(vid);
102 length = sprintf(buffer,
109 ,atomic_read(&vxi->vx_usecnt)
110 ,atomic_read(&vxi->vx_tasks)
111 ,(unsigned long long)vxi->vx_flags
112 ,(unsigned long long)vxi->vx_bcaps
113 ,(unsigned long long)vxi->vx_ccaps
114 ,atomic_read(&vxi->limit.ticks)
120 int proc_xid_limit (int vid, char *buffer)
125 vxi = lookup_vx_info(vid);
128 length = vx_info_proc_limit(&vxi->limit, buffer);
133 int proc_xid_sched (int vid, char *buffer)
138 vxi = lookup_vx_info(vid);
141 length = vx_info_proc_sched(&vxi->sched, buffer);
146 int proc_xid_cvirt (int vid, char *buffer)
151 vxi = lookup_vx_info(vid);
155 length = vx_info_proc_cvirt(&vxi->cvirt, buffer);
160 int proc_xid_cacct (int vid, char *buffer)
165 vxi = lookup_vx_info(vid);
168 length = vx_info_proc_cacct(&vxi->cacct, buffer);
174 static int proc_vnet_info(int vid, char *buffer)
176 return sprintf(buffer,
177 "VCIVersion:\t%04x:%04x\n"
180 ,VCI_VERSION & 0xFFFF
186 int proc_nid_info (int vid, char *buffer)
191 nxi = lookup_nx_info(vid);
194 length = sprintf(buffer,
200 for (i=0; i<nxi->nbipv4; i++) {
201 length += sprintf(buffer + length,
202 "%d:\t" NIPQUAD_FMT "/" NIPQUAD_FMT "\n", i,
203 NIPQUAD(nxi->ipv4[i]), NIPQUAD(nxi->mask[i]));
209 int proc_nid_status (int vid, char *buffer)
214 nxi = lookup_nx_info(vid);
217 length = sprintf(buffer,
221 ,atomic_read(&nxi->nx_usecnt)
222 ,atomic_read(&nxi->nx_tasks)
223 ,(unsigned long long)nxi->nx_flags
229 /* here the inode helpers */
232 #define fake_ino(id,nr) (((nr) & 0xFFFF) | \
233 (((id) & 0xFFFF) << 16))
235 #define inode_vid(i) (((i)->i_ino >> 16) & 0xFFFF)
236 #define inode_type(i) ((i)->i_ino & 0xFFFF)
238 #define MAX_MULBY10 ((~0U-9)/10)
241 static struct inode *proc_vid_make_inode(struct super_block * sb,
244 struct inode *inode = new_inode(sb);
249 inode->i_mtime = inode->i_atime =
250 inode->i_ctime = CURRENT_TIME;
251 inode->i_ino = fake_ino(vid, ino);
259 static int proc_vid_revalidate(struct dentry * dentry, struct nameidata *nd)
261 struct inode * inode = dentry->d_inode;
264 vid = inode_vid(inode);
265 switch (inode_type(inode) & PROC_VID_MASK) {
267 hashed = xid_is_hashed(vid);
270 hashed = nid_is_hashed(vid);
280 #define PROC_BLOCK_SIZE (PAGE_SIZE - 1024)
282 static ssize_t proc_vid_info_read(struct file * file, char __user * buf,
283 size_t count, loff_t *ppos)
285 struct inode * inode = file->f_dentry->d_inode;
290 if (count > PROC_BLOCK_SIZE)
291 count = PROC_BLOCK_SIZE;
292 if (!(page = __get_free_page(GFP_KERNEL)))
295 vid = inode_vid(inode);
296 length = PROC_I(inode)->op.proc_vid_read(vid, (char*)page);
299 length = simple_read_from_buffer(buf, count, ppos,
300 (char *)page, length);
309 /* here comes the lower level (vid) */
311 static struct file_operations proc_vid_info_file_operations = {
312 .read = proc_vid_info_read,
315 static struct dentry_operations proc_vid_dentry_operations = {
316 .d_revalidate = proc_vid_revalidate,
327 #define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
329 static struct vid_entry vx_base_stuff[] = {
330 E(PROC_XID_INFO, "info", S_IFREG|S_IRUGO),
331 E(PROC_XID_STATUS, "status", S_IFREG|S_IRUGO),
332 E(PROC_XID_LIMIT, "limit", S_IFREG|S_IRUGO),
333 E(PROC_XID_SCHED, "sched", S_IFREG|S_IRUGO),
334 E(PROC_XID_CVIRT, "cvirt", S_IFREG|S_IRUGO),
335 E(PROC_XID_CACCT, "cacct", S_IFREG|S_IRUGO),
339 static struct vid_entry vn_base_stuff[] = {
340 E(PROC_NID_INFO, "info", S_IFREG|S_IRUGO),
341 E(PROC_NID_STATUS, "status", S_IFREG|S_IRUGO),
347 static struct dentry *proc_vid_lookup(struct inode *dir,
348 struct dentry *dentry, struct nameidata *nd)
357 switch (inode_type(dir)) {
368 for (; p->name; p++) {
369 if (p->len != dentry->d_name.len)
371 if (!memcmp(dentry->d_name.name, p->name, p->len))
378 inode = proc_vid_make_inode(dir->i_sb, inode_vid(dir), p->type);
384 PROC_I(inode)->op.proc_vid_read = proc_xid_info;
386 case PROC_XID_STATUS:
387 PROC_I(inode)->op.proc_vid_read = proc_xid_status;
390 PROC_I(inode)->op.proc_vid_read = proc_xid_limit;
393 PROC_I(inode)->op.proc_vid_read = proc_xid_sched;
396 PROC_I(inode)->op.proc_vid_read = proc_xid_cvirt;
399 PROC_I(inode)->op.proc_vid_read = proc_xid_cacct;
403 PROC_I(inode)->op.proc_vid_read = proc_nid_info;
405 case PROC_NID_STATUS:
406 PROC_I(inode)->op.proc_vid_read = proc_nid_status;
410 printk("procfs: impossible type (%d)",p->type);
412 return ERR_PTR(-EINVAL);
414 inode->i_mode = p->mode;
415 inode->i_fop = &proc_vid_info_file_operations;
417 inode->i_flags|=S_IMMUTABLE;
419 dentry->d_op = &proc_vid_dentry_operations;
420 d_add(dentry, inode);
423 return ERR_PTR(error);
427 static int proc_vid_readdir(struct file * filp,
428 void * dirent, filldir_t filldir)
431 struct inode *inode = filp->f_dentry->d_inode;
437 if (filldir(dirent, ".", 1, i,
438 inode->i_ino, DT_DIR) < 0)
444 if (filldir(dirent, "..", 2, i,
445 PROC_ROOT_INO, DT_DIR) < 0)
452 switch (inode_type(inode)) {
454 size = sizeof(vx_base_stuff);
455 p = vx_base_stuff + i;
458 size = sizeof(vn_base_stuff);
459 p = vn_base_stuff + i;
464 if (i >= size/sizeof(struct vid_entry))
467 if (filldir(dirent, p->name, p->len,
468 filp->f_pos, fake_ino(inode_vid(inode),
469 p->type), p->mode >> 12) < 0)
481 /* now the upper level (virtual) */
483 static struct file_operations proc_vid_file_operations = {
484 .read = generic_read_dir,
485 .readdir = proc_vid_readdir,
488 static struct inode_operations proc_vid_inode_operations = {
489 .lookup = proc_vid_lookup,
494 static __inline__ int atovid(const char *str, int len)
504 if (vid >= MAX_MULBY10)
515 struct dentry *proc_virtual_lookup(struct inode *dir,
516 struct dentry * dentry, struct nameidata *nd)
523 name = dentry->d_name.name;
524 len = dentry->d_name.len;
527 if (len == 7 && !memcmp(name, "current", 7)) {
528 inode = new_inode(dir->i_sb);
531 inode->i_mtime = inode->i_atime =
532 inode->i_ctime = CURRENT_TIME;
533 inode->i_ino = fake_ino(1, PROC_XID_INO);
534 inode->i_mode = S_IFLNK|S_IRWXUGO;
535 inode->i_uid = inode->i_gid = 0;
536 d_add(dentry, inode);
539 if (len == 4 && !memcmp(name, "info", 4)) {
540 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_XID_INFO);
543 inode->i_fop = &proc_vid_info_file_operations;
544 PROC_I(inode)->op.proc_vid_read = proc_virtual_info;
545 inode->i_mode = S_IFREG|S_IRUGO;
546 d_add(dentry, inode);
551 xid = atovid(name, len);
554 vxi = lookup_vx_info(xid);
559 if (vx_check(xid, VX_ADMIN|VX_WATCH|VX_IDENT))
560 inode = proc_vid_make_inode(dir->i_sb,
561 vxi->vx_id, PROC_XID_INO);
565 inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
566 inode->i_op = &proc_vid_inode_operations;
567 inode->i_fop = &proc_vid_file_operations;
569 inode->i_flags|=S_IMMUTABLE;
571 dentry->d_op = &proc_vid_dentry_operations;
572 d_add(dentry, inode);
582 struct dentry *proc_vnet_lookup(struct inode *dir,
583 struct dentry * dentry, struct nameidata *nd)
590 name = dentry->d_name.name;
591 len = dentry->d_name.len;
593 if (len == 7 && !memcmp(name, "current", 7)) {
594 inode = new_inode(dir->i_sb);
597 inode->i_mtime = inode->i_atime =
598 inode->i_ctime = CURRENT_TIME;
599 inode->i_ino = fake_ino(1, PROC_NID_INO);
600 inode->i_mode = S_IFLNK|S_IRWXUGO;
601 inode->i_uid = inode->i_gid = 0;
602 d_add(dentry, inode);
605 if (len == 4 && !memcmp(name, "info", 4)) {
606 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_NID_INFO);
609 inode->i_fop = &proc_vid_info_file_operations;
610 PROC_I(inode)->op.proc_vid_read = proc_vnet_info;
611 inode->i_mode = S_IFREG|S_IRUGO;
612 d_add(dentry, inode);
617 nid = atovid(name, len);
620 nxi = lookup_nx_info(nid);
626 inode = proc_vid_make_inode(dir->i_sb,
627 nxi->nx_id, PROC_NID_INO);
631 inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
632 inode->i_op = &proc_vid_inode_operations;
633 inode->i_fop = &proc_vid_file_operations;
635 inode->i_flags|=S_IMMUTABLE;
637 dentry->d_op = &proc_vid_dentry_operations;
638 d_add(dentry, inode);
650 #define PROC_NUMBUF 10
651 #define PROC_MAXVIDS 32
653 int proc_virtual_readdir(struct file * filp,
654 void * dirent, filldir_t filldir)
656 unsigned int xid_array[PROC_MAXVIDS];
657 char buf[PROC_NUMBUF];
658 unsigned int nr = filp->f_pos-3;
659 unsigned int nr_xids, i;
662 switch ((long)filp->f_pos) {
664 ino = fake_ino(0, PROC_XID_INO);
665 if (filldir(dirent, ".", 1,
666 filp->f_pos, ino, DT_DIR) < 0)
671 ino = filp->f_dentry->d_parent->d_inode->i_ino;
672 if (filldir(dirent, "..", 2,
673 filp->f_pos, ino, DT_DIR) < 0)
678 ino = fake_ino(0, PROC_XID_INFO);
679 if (filldir(dirent, "info", 4,
680 filp->f_pos, ino, DT_LNK) < 0)
685 if (vx_current_xid() > 1) {
686 ino = fake_ino(1, PROC_XID_INO);
687 if (filldir(dirent, "current", 7,
688 filp->f_pos, ino, DT_LNK) < 0)
694 nr_xids = get_xid_list(nr, xid_array, PROC_MAXVIDS);
695 for (i = 0; i < nr_xids; i++) {
696 int xid = xid_array[i];
697 ino_t ino = fake_ino(xid, PROC_XID_INO);
698 unsigned int j = PROC_NUMBUF;
700 do buf[--j] = '0' + (xid % 10); while (xid/=10);
702 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
703 filp->f_pos, ino, DT_DIR) < 0)
711 static struct file_operations proc_virtual_dir_operations = {
712 .read = generic_read_dir,
713 .readdir = proc_virtual_readdir,
716 static struct inode_operations proc_virtual_dir_inode_operations = {
717 .lookup = proc_virtual_lookup,
721 int proc_vnet_readdir(struct file * filp,
722 void * dirent, filldir_t filldir)
724 unsigned int nid_array[PROC_MAXVIDS];
725 char buf[PROC_NUMBUF];
726 unsigned int nr = filp->f_pos-2;
727 unsigned int nr_nids, i;
730 switch ((long)filp->f_pos) {
732 ino = fake_ino(0, PROC_NID_INO);
733 if (filldir(dirent, ".", 1,
734 filp->f_pos, ino, DT_DIR) < 0)
739 ino = filp->f_dentry->d_parent->d_inode->i_ino;
740 if (filldir(dirent, "..", 2,
741 filp->f_pos, ino, DT_DIR) < 0)
746 ino = fake_ino(0, PROC_NID_INFO);
747 if (filldir(dirent, "info", 4,
748 filp->f_pos, ino, DT_REG) < 0)
754 nr_nids = get_nid_list(nr, nid_array, PROC_MAXVIDS);
755 for (i = 0; i < nr_nids; i++) {
756 int nid = nid_array[i];
757 ino_t ino = fake_ino(nid, PROC_NID_INO);
758 unsigned long j = PROC_NUMBUF;
760 do buf[--j] = '0' + (nid % 10); while (nid/=10);
762 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
763 filp->f_pos, ino, DT_DIR) < 0)
771 static struct file_operations proc_vnet_dir_operations = {
772 .read = generic_read_dir,
773 .readdir = proc_vnet_readdir,
776 static struct inode_operations proc_vnet_dir_inode_operations = {
777 .lookup = proc_vnet_lookup,
782 void proc_vx_init(void)
784 struct proc_dir_entry *ent;
786 ent = proc_mkdir("virtual", 0);
788 ent->proc_fops = &proc_virtual_dir_operations;
789 ent->proc_iops = &proc_virtual_dir_inode_operations;
793 ent = proc_mkdir("virtnet", 0);
795 ent->proc_fops = &proc_vnet_dir_operations;
796 ent->proc_iops = &proc_vnet_dir_inode_operations;
807 int proc_pid_vx_info(struct task_struct *p, char *buffer)
810 char * orig = buffer;
812 buffer += sprintf (buffer,"XID:\t%d\n", vx_task_xid(p));
813 if (vx_flags(VXF_INFO_HIDE, 0))
816 vxi = task_get_vx_info(p);
820 buffer += sprintf (buffer,"BCaps:\t%016llx\n"
821 ,(unsigned long long)vxi->vx_bcaps);
822 buffer += sprintf (buffer,"CCaps:\t%016llx\n"
823 ,(unsigned long long)vxi->vx_ccaps);
824 buffer += sprintf (buffer,"CFlags:\t%016llx\n"
825 ,(unsigned long long)vxi->vx_flags);
826 buffer += sprintf (buffer,"CIPid:\t%d\n"
831 return buffer - orig;
835 int proc_pid_nx_info(struct task_struct *p, char *buffer)
838 char * orig = buffer;
841 buffer += sprintf (buffer,"NID:\t%d\n", nx_task_nid(p));
842 if (vx_flags(VXF_INFO_HIDE, 0))
844 nxi = task_get_nx_info(p);
848 for (i=0; i<nxi->nbipv4; i++){
849 buffer += sprintf (buffer,
850 "V4Root[%d]:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i
851 ,NIPQUAD(nxi->ipv4[i])
852 ,NIPQUAD(nxi->mask[i]));
854 buffer += sprintf (buffer,
855 "V4Root[bcast]:\t%d.%d.%d.%d\n"
856 ,NIPQUAD(nxi->v4_bcast));
860 return buffer - orig;