2 * linux/kernel/vserver/proc.c
4 * Virtual Context Support
6 * Copyright (C) 2003-2004 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"
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"
72 int proc_xid_info (int vid, char *buffer)
77 vxi = locate_vx_info(vid);
80 length = sprintf(buffer,
92 int proc_xid_status (int vid, char *buffer)
97 vxi = locate_vx_info(vid);
100 length = sprintf(buffer,
107 ,atomic_read(&vxi->vx_usecnt)
108 ,atomic_read(&vxi->vx_refcnt)
109 ,(unsigned long long)vxi->vx_flags
110 ,(unsigned long long)vxi->vx_bcaps
111 ,(unsigned long long)vxi->vx_ccaps
112 ,atomic_read(&vxi->limit.ticks)
118 int proc_xid_limit (int vid, char *buffer)
123 vxi = locate_vx_info(vid);
126 length = vx_info_proc_limit(&vxi->limit, buffer);
131 int proc_xid_sched (int vid, char *buffer)
136 vxi = locate_vx_info(vid);
139 length = vx_info_proc_sched(&vxi->sched, buffer);
144 int proc_xid_cvirt (int vid, char *buffer)
149 vxi = locate_vx_info(vid);
153 length = vx_info_proc_cvirt(&vxi->cvirt, buffer);
158 int proc_xid_cacct (int vid, char *buffer)
163 vxi = locate_vx_info(vid);
166 length = vx_info_proc_cacct(&vxi->cacct, buffer);
172 static int proc_vnet_info(int vid, char *buffer)
174 return sprintf(buffer,
175 "VCIVersion:\t%04x:%04x\n"
178 ,VCI_VERSION & 0xFFFF
184 (((a)>>0) & 0xff), (((a)>>8) & 0xff), \
185 (((a)>>16) & 0xff), (((a)>>24) & 0xff)
187 int proc_nid_info (int vid, char *buffer)
192 nxi = locate_nx_info(vid);
195 length = sprintf(buffer,
201 for (i=0; i<nxi->nbipv4; i++) {
202 length += sprintf(buffer + length,
203 "%d:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i,
204 atoquad(nxi->ipv4[i]),
205 atoquad(nxi->mask[i]));
211 int proc_nid_status (int vid, char *buffer)
216 nxi = locate_nx_info(vid);
219 length = sprintf(buffer,
222 ,atomic_read(&nxi->nx_usecnt)
223 ,atomic_read(&nxi->nx_refcnt)
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);
255 // inode->i_xid = xid;
260 static int proc_vid_revalidate(struct dentry * dentry, struct nameidata *nd)
262 struct inode * inode = dentry->d_inode;
265 vid = inode_vid(inode);
266 switch (inode_type(inode) & PROC_VID_MASK) {
268 hashed = vx_info_is_hashed(vid);
271 hashed = nx_info_is_hashed(vid);
281 static int proc_vid_delete_dentry(struct dentry * dentry)
288 #define PROC_BLOCK_SIZE (PAGE_SIZE - 1024)
290 static ssize_t proc_vid_info_read(struct file * file, char * buf,
291 size_t count, loff_t *ppos)
293 struct inode * inode = file->f_dentry->d_inode;
299 if (count > PROC_BLOCK_SIZE)
300 count = PROC_BLOCK_SIZE;
301 if (!(page = __get_free_page(GFP_KERNEL)))
304 vid = inode_vid(inode);
305 length = PROC_I(inode)->op.proc_vid_read(vid, (char*)page);
311 /* Static 4kB (or whatever) block capacity */
312 if (*ppos >= length) {
316 if (count + *ppos > length)
317 count = length - *ppos;
319 copy_to_user(buf, (char *) page + *ppos, count);
329 /* here comes the lower level (vid) */
331 static struct file_operations proc_vid_info_file_operations = {
332 read: proc_vid_info_read,
335 static struct dentry_operations proc_vid_dentry_operations = {
336 d_revalidate: proc_vid_revalidate,
337 // d_delete: proc_vid_delete_dentry,
348 #define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
350 static struct vid_entry vx_base_stuff[] = {
351 E(PROC_XID_INFO, "info", S_IFREG|S_IRUGO),
352 E(PROC_XID_STATUS, "status", S_IFREG|S_IRUGO),
353 E(PROC_XID_LIMIT, "limit", S_IFREG|S_IRUGO),
354 E(PROC_XID_SCHED, "sched", S_IFREG|S_IRUGO),
355 E(PROC_XID_CVIRT, "cvirt", S_IFREG|S_IRUGO),
356 E(PROC_XID_CACCT, "cacct", S_IFREG|S_IRUGO),
360 static struct vid_entry vn_base_stuff[] = {
361 E(PROC_NID_INFO, "info", S_IFREG|S_IRUGO),
362 E(PROC_NID_STATUS, "status", S_IFREG|S_IRUGO),
368 static struct dentry *proc_vid_lookup(struct inode *dir,
369 struct dentry *dentry, struct nameidata *nd)
378 switch (inode_type(dir)) {
389 for (; p->name; p++) {
390 if (p->len != dentry->d_name.len)
392 if (!memcmp(dentry->d_name.name, p->name, p->len))
399 inode = proc_vid_make_inode(dir->i_sb, inode_vid(dir), p->type);
405 PROC_I(inode)->op.proc_vid_read = proc_xid_info;
407 case PROC_XID_STATUS:
408 PROC_I(inode)->op.proc_vid_read = proc_xid_status;
411 PROC_I(inode)->op.proc_vid_read = proc_xid_limit;
414 PROC_I(inode)->op.proc_vid_read = proc_xid_sched;
417 PROC_I(inode)->op.proc_vid_read = proc_xid_cvirt;
420 PROC_I(inode)->op.proc_vid_read = proc_xid_cacct;
424 PROC_I(inode)->op.proc_vid_read = proc_nid_info;
426 case PROC_NID_STATUS:
427 PROC_I(inode)->op.proc_vid_read = proc_nid_status;
431 printk("procfs: impossible type (%d)",p->type);
433 return ERR_PTR(-EINVAL);
435 inode->i_mode = p->mode;
436 // inode->i_op = &proc_vid_info_inode_operations;
437 inode->i_fop = &proc_vid_info_file_operations;
439 inode->i_flags|=S_IMMUTABLE;
441 dentry->d_op = &proc_vid_dentry_operations;
442 d_add(dentry, inode);
445 return ERR_PTR(error);
449 static int proc_vid_readdir(struct file * filp,
450 void * dirent, filldir_t filldir)
453 struct inode *inode = filp->f_dentry->d_inode;
459 if (filldir(dirent, ".", 1, i,
460 inode->i_ino, DT_DIR) < 0)
466 if (filldir(dirent, "..", 2, i,
467 PROC_ROOT_INO, DT_DIR) < 0)
474 switch (inode_type(inode)) {
476 size = sizeof(vx_base_stuff);
477 p = vx_base_stuff + i;
480 size = sizeof(vn_base_stuff);
481 p = vn_base_stuff + i;
486 if (i >= size/sizeof(struct vid_entry))
489 if (filldir(dirent, p->name, p->len,
490 filp->f_pos, fake_ino(inode_vid(inode),
491 p->type), p->mode >> 12) < 0)
503 /* now the upper level (virtual) */
505 static struct file_operations proc_vid_file_operations = {
506 read: generic_read_dir,
507 readdir: proc_vid_readdir,
510 static struct inode_operations proc_vid_inode_operations = {
511 lookup: proc_vid_lookup,
516 static __inline__ int atovid(const char *str, int len)
526 if (vid >= MAX_MULBY10)
537 struct dentry *proc_virtual_lookup(struct inode *dir,
538 struct dentry * dentry, struct nameidata *nd)
545 name = dentry->d_name.name;
546 len = dentry->d_name.len;
549 if (len == 7 && !memcmp(name, "current", 7)) {
550 inode = new_inode(dir->i_sb);
553 inode->i_mtime = inode->i_atime =
554 inode->i_ctime = CURRENT_TIME;
555 inode->i_ino = fake_ino(1, PROC_XID_INO);
556 inode->i_mode = S_IFLNK|S_IRWXUGO;
557 inode->i_uid = inode->i_gid = 0;
559 // inode->i_op = &proc_current_inode_operations;
560 d_add(dentry, inode);
563 if (len == 4 && !memcmp(name, "info", 4)) {
564 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_XID_INFO);
567 inode->i_fop = &proc_vid_info_file_operations;
568 PROC_I(inode)->op.proc_vid_read = proc_virtual_info;
569 inode->i_mode = S_IFREG|S_IRUGO;
570 // inode->i_size = 64;
571 // inode->i_op = &proc_current_inode_operations;
572 d_add(dentry, inode);
577 xid = atovid(name, len);
580 vxi = locate_vx_info(xid);
585 if (vx_check(xid, VX_ADMIN|VX_WATCH|VX_IDENT))
586 inode = proc_vid_make_inode(dir->i_sb,
587 vxi->vx_id, PROC_XID_INO);
591 inode->i_mode = S_IFDIR|S_IRUGO;
592 inode->i_op = &proc_vid_inode_operations;
593 inode->i_fop = &proc_vid_file_operations;
595 inode->i_flags|=S_IMMUTABLE;
597 dentry->d_op = &proc_vid_dentry_operations;
598 d_add(dentry, inode);
608 struct dentry *proc_vnet_lookup(struct inode *dir,
609 struct dentry * dentry, struct nameidata *nd)
616 name = dentry->d_name.name;
617 len = dentry->d_name.len;
619 if (len == 7 && !memcmp(name, "current", 7)) {
620 inode = new_inode(dir->i_sb);
623 inode->i_mtime = inode->i_atime =
624 inode->i_ctime = CURRENT_TIME;
625 inode->i_ino = fake_ino(1, PROC_NID_INO);
626 inode->i_mode = S_IFLNK|S_IRWXUGO;
627 inode->i_uid = inode->i_gid = 0;
629 // inode->i_op = &proc_current_inode_operations;
630 d_add(dentry, inode);
633 if (len == 4 && !memcmp(name, "info", 4)) {
634 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_NID_INFO);
637 inode->i_fop = &proc_vid_info_file_operations;
638 PROC_I(inode)->op.proc_vid_read = proc_vnet_info;
639 inode->i_mode = S_IFREG|S_IRUGO;
640 // inode->i_size = 64;
641 // inode->i_op = &proc_current_inode_operations;
642 d_add(dentry, inode);
647 nid = atovid(name, len);
650 nxi = locate_nx_info(nid);
656 inode = proc_vid_make_inode(dir->i_sb,
657 nxi->nx_id, PROC_NID_INO);
661 inode->i_mode = S_IFDIR|S_IRUGO;
662 inode->i_op = &proc_vid_inode_operations;
663 inode->i_fop = &proc_vid_file_operations;
665 inode->i_flags|=S_IMMUTABLE;
667 dentry->d_op = &proc_vid_dentry_operations;
668 d_add(dentry, inode);
680 #define PROC_NUMBUF 10
681 #define PROC_MAXVIDS 32
683 int proc_virtual_readdir(struct file * filp,
684 void * dirent, filldir_t filldir)
686 unsigned int xid_array[PROC_MAXVIDS];
687 char buf[PROC_NUMBUF];
688 unsigned int nr = filp->f_pos-3;
689 unsigned int nr_xids, i;
692 switch ((long)filp->f_pos) {
694 ino = fake_ino(0, PROC_XID_INO);
695 if (filldir(dirent, ".", 1,
696 filp->f_pos, ino, DT_DIR) < 0)
701 ino = filp->f_dentry->d_parent->d_inode->i_ino;
702 if (filldir(dirent, "..", 2,
703 filp->f_pos, ino, DT_DIR) < 0)
708 ino = fake_ino(0, PROC_XID_INFO);
709 if (filldir(dirent, "info", 4,
710 filp->f_pos, ino, DT_LNK) < 0)
715 if (vx_current_xid() > 1) {
716 ino = fake_ino(1, PROC_XID_INO);
717 if (filldir(dirent, "current", 7,
718 filp->f_pos, ino, DT_LNK) < 0)
724 nr_xids = get_xid_list(nr, xid_array, PROC_MAXVIDS);
725 for (i = 0; i < nr_xids; i++) {
726 int xid = xid_array[i];
727 ino_t ino = fake_ino(xid, PROC_XID_INO);
728 unsigned int j = PROC_NUMBUF;
730 do buf[--j] = '0' + (xid % 10); while (xid/=10);
732 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
733 filp->f_pos, ino, DT_DIR) < 0)
741 static struct file_operations proc_virtual_dir_operations = {
742 read: generic_read_dir,
743 readdir: proc_virtual_readdir,
746 static struct inode_operations proc_virtual_dir_inode_operations = {
747 lookup: proc_virtual_lookup,
751 int proc_vnet_readdir(struct file * filp,
752 void * dirent, filldir_t filldir)
754 unsigned int nid_array[PROC_MAXVIDS];
755 char buf[PROC_NUMBUF];
756 unsigned int nr = filp->f_pos-3;
757 unsigned int nr_nids, i;
760 switch ((long)filp->f_pos) {
762 ino = fake_ino(0, PROC_NID_INO);
763 if (filldir(dirent, ".", 1,
764 filp->f_pos, ino, DT_DIR) < 0)
769 ino = filp->f_dentry->d_parent->d_inode->i_ino;
770 if (filldir(dirent, "..", 2,
771 filp->f_pos, ino, DT_DIR) < 0)
776 ino = fake_ino(0, PROC_NID_INFO);
777 if (filldir(dirent, "info", 4,
778 filp->f_pos, ino, DT_LNK) < 0)
783 if (vx_current_xid() > 1) {
784 ino = fake_ino(1, PROC_NID_INO);
785 if (filldir(dirent, "current", 7,
786 filp->f_pos, ino, DT_LNK) < 0)
792 nr_nids = get_nid_list(nr, nid_array, PROC_MAXVIDS);
793 for (i = 0; i < nr_nids; i++) {
794 int nid = nid_array[i];
795 ino_t ino = fake_ino(nid, PROC_NID_INO);
796 unsigned long j = PROC_NUMBUF;
798 do buf[--j] = '0' + (nid % 10); while (nid/=10);
800 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
801 filp->f_pos, ino, DT_DIR) < 0)
809 static struct file_operations proc_vnet_dir_operations = {
810 read: generic_read_dir,
811 readdir: proc_vnet_readdir,
814 static struct inode_operations proc_vnet_dir_inode_operations = {
815 lookup: proc_vnet_lookup,
820 void proc_vx_init(void)
822 struct proc_dir_entry *ent;
824 ent = proc_mkdir("virtual", 0);
826 ent->proc_fops = &proc_virtual_dir_operations;
827 ent->proc_iops = &proc_virtual_dir_inode_operations;
831 ent = proc_mkdir("virtnet", 0);
833 ent->proc_fops = &proc_vnet_dir_operations;
834 ent->proc_iops = &proc_vnet_dir_inode_operations;
845 char *task_vx_info(struct task_struct *p, char *buffer)
849 buffer += sprintf (buffer,"XID:\t%d\n", vx_task_xid(p));
850 vxi = task_get_vx_info(p);
851 if (vxi && !vx_flags(VXF_INFO_HIDE, 0)) {
852 buffer += sprintf (buffer,"BCaps:\t%016llx\n"
853 ,(unsigned long long)vxi->vx_bcaps);
854 buffer += sprintf (buffer,"CCaps:\t%016llx\n"
855 ,(unsigned long long)vxi->vx_ccaps);
856 buffer += sprintf (buffer,"CFlags:\t%016llx\n"
857 ,(unsigned long long)vxi->vx_flags);
858 buffer += sprintf (buffer,"CIPid:\t%d\n"
865 int proc_pid_vx_info(struct task_struct *p, char *buffer)
867 char * orig = buffer;
869 buffer = task_vx_info(p, buffer);
870 return buffer - orig;
873 char *task_nx_info(struct task_struct *p, char *buffer)
877 buffer += sprintf (buffer,"NID:\t%d\n", nx_task_nid(p));
878 nxi = task_get_nx_info(p);
879 if (nxi && !vx_flags(VXF_INFO_HIDE, 0)) {
882 for (i=0; i<nxi->nbipv4; i++){
883 buffer += sprintf (buffer,
884 "V4Root[%d]:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i
885 ,NIPQUAD(nxi->ipv4[i])
886 ,NIPQUAD(nxi->mask[i]));
888 buffer += sprintf (buffer,
889 "V4Root[bcast]:\t%d.%d.%d.%d\n"
890 ,NIPQUAD(nxi->v4_bcast));
896 int proc_pid_nx_info(struct task_struct *p, char *buffer)
898 char * orig = buffer;
900 buffer = task_nx_info(p, buffer);
901 return buffer - orig;