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/vserver.h>
22 #include <linux/vs_base.h>
23 #include <linux/vs_context.h>
24 #include <linux/vs_network.h>
25 #include <linux/vs_cvirt.h>
27 #include <asm/uaccess.h>
28 #include <asm/unistd.h>
31 static struct proc_dir_entry *proc_virtual;
33 static struct proc_dir_entry *proc_vnet;
36 enum vid_directory_inos {
50 #define PROC_VID_MASK 0x60
53 /* first the actual feeds */
56 static int proc_virtual_info(int vid, char *buffer)
58 return sprintf(buffer,
59 "VCIVersion:\t%04x:%04x\n"
68 int proc_xid_info (int vid, char *buffer)
73 vxi = locate_vx_info(vid);
76 length = sprintf(buffer,
88 int proc_xid_status (int vid, char *buffer)
93 vxi = locate_vx_info(vid);
96 length = sprintf(buffer,
103 ,atomic_read(&vxi->vx_usecnt)
104 ,atomic_read(&vxi->vx_refcnt)
105 ,(unsigned long long)vxi->vx_flags
106 ,(unsigned long long)vxi->vx_bcaps
107 ,(unsigned long long)vxi->vx_ccaps
108 ,atomic_read(&vxi->limit.ticks)
114 int proc_xid_limit (int vid, char *buffer)
119 vxi = locate_vx_info(vid);
122 length = vx_info_proc_limit(&vxi->limit, buffer);
127 int proc_xid_sched (int vid, char *buffer)
132 vxi = locate_vx_info(vid);
135 length = vx_info_proc_sched(&vxi->sched, buffer);
140 int proc_xid_cvirt (int vid, char *buffer)
145 vxi = locate_vx_info(vid);
149 length = vx_info_proc_cvirt(&vxi->cvirt, buffer);
154 int proc_xid_cacct (int vid, char *buffer)
159 vxi = locate_vx_info(vid);
162 length = vx_info_proc_cacct(&vxi->cacct, buffer);
168 static int proc_vnet_info(int vid, char *buffer)
170 return sprintf(buffer,
171 "VCIVersion:\t%04x:%04x\n"
174 ,VCI_VERSION & 0xFFFF
180 (((a)>>0) & 0xff), (((a)>>8) & 0xff), \
181 (((a)>>16) & 0xff), (((a)>>24) & 0xff)
183 int proc_nid_info (int vid, char *buffer)
188 nxi = locate_nx_info(vid);
191 length = sprintf(buffer,
197 for (i=0; i<nxi->nbipv4; i++) {
198 length += sprintf(buffer + length,
199 "%d:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i,
200 atoquad(nxi->ipv4[i]),
201 atoquad(nxi->mask[i]));
207 int proc_nid_status (int vid, char *buffer)
212 nxi = locate_nx_info(vid);
215 length = sprintf(buffer,
218 ,atomic_read(&nxi->nx_usecnt)
219 ,atomic_read(&nxi->nx_refcnt)
225 /* here the inode helpers */
228 #define fake_ino(id,nr) (((nr) & 0xFFFF) | \
229 (((id) & 0xFFFF) << 16))
231 #define inode_vid(i) (((i)->i_ino >> 16) & 0xFFFF)
232 #define inode_type(i) ((i)->i_ino & 0xFFFF)
234 #define MAX_MULBY10 ((~0U-9)/10)
237 static struct inode *proc_vid_make_inode(struct super_block * sb,
240 struct inode *inode = new_inode(sb);
245 inode->i_mtime = inode->i_atime =
246 inode->i_ctime = CURRENT_TIME;
247 inode->i_ino = fake_ino(vid, ino);
251 // inode->i_xid = xid;
256 static int proc_vid_revalidate(struct dentry * dentry, struct nameidata *nd)
258 struct inode * inode = dentry->d_inode;
261 vid = inode_vid(inode);
262 switch (inode_type(inode) & PROC_VID_MASK) {
264 hashed = vx_info_is_hashed(vid);
267 hashed = nx_info_is_hashed(vid);
277 static int proc_vid_delete_dentry(struct dentry * dentry)
284 #define PROC_BLOCK_SIZE (PAGE_SIZE - 1024)
286 static ssize_t proc_vid_info_read(struct file * file, char * buf,
287 size_t count, loff_t *ppos)
289 struct inode * inode = file->f_dentry->d_inode;
295 if (count > PROC_BLOCK_SIZE)
296 count = PROC_BLOCK_SIZE;
297 if (!(page = __get_free_page(GFP_KERNEL)))
300 vid = inode_vid(inode);
301 length = PROC_I(inode)->op.proc_vid_read(vid, (char*)page);
307 /* Static 4kB (or whatever) block capacity */
308 if (*ppos >= length) {
312 if (count + *ppos > length)
313 count = length - *ppos;
315 copy_to_user(buf, (char *) page + *ppos, count);
325 /* here comes the lower level (vid) */
327 static struct file_operations proc_vid_info_file_operations = {
328 read: proc_vid_info_read,
331 static struct dentry_operations proc_vid_dentry_operations = {
332 d_revalidate: proc_vid_revalidate,
333 // d_delete: proc_vid_delete_dentry,
344 #define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
346 static struct vid_entry vx_base_stuff[] = {
347 E(PROC_XID_INFO, "info", S_IFREG|S_IRUGO),
348 E(PROC_XID_STATUS, "status", S_IFREG|S_IRUGO),
349 E(PROC_XID_LIMIT, "limit", S_IFREG|S_IRUGO),
350 E(PROC_XID_SCHED, "sched", S_IFREG|S_IRUGO),
351 E(PROC_XID_CVIRT, "cvirt", S_IFREG|S_IRUGO),
352 E(PROC_XID_CACCT, "cacct", S_IFREG|S_IRUGO),
356 static struct vid_entry vn_base_stuff[] = {
357 E(PROC_NID_INFO, "info", S_IFREG|S_IRUGO),
358 E(PROC_NID_STATUS, "status", S_IFREG|S_IRUGO),
364 static struct dentry *proc_vid_lookup(struct inode *dir,
365 struct dentry *dentry, struct nameidata *nd)
374 switch (inode_type(dir)) {
385 for (; p->name; p++) {
386 if (p->len != dentry->d_name.len)
388 if (!memcmp(dentry->d_name.name, p->name, p->len))
395 inode = proc_vid_make_inode(dir->i_sb, inode_vid(dir), p->type);
401 PROC_I(inode)->op.proc_vid_read = proc_xid_info;
403 case PROC_XID_STATUS:
404 PROC_I(inode)->op.proc_vid_read = proc_xid_status;
407 PROC_I(inode)->op.proc_vid_read = proc_xid_limit;
410 PROC_I(inode)->op.proc_vid_read = proc_xid_sched;
413 PROC_I(inode)->op.proc_vid_read = proc_xid_cvirt;
416 PROC_I(inode)->op.proc_vid_read = proc_xid_cacct;
420 PROC_I(inode)->op.proc_vid_read = proc_nid_info;
422 case PROC_NID_STATUS:
423 PROC_I(inode)->op.proc_vid_read = proc_nid_status;
427 printk("procfs: impossible type (%d)",p->type);
429 return ERR_PTR(-EINVAL);
431 inode->i_mode = p->mode;
432 // inode->i_op = &proc_vid_info_inode_operations;
433 inode->i_fop = &proc_vid_info_file_operations;
435 inode->i_flags|=S_IMMUTABLE;
437 dentry->d_op = &proc_vid_dentry_operations;
438 d_add(dentry, inode);
441 return ERR_PTR(error);
445 static int proc_vid_readdir(struct file * filp,
446 void * dirent, filldir_t filldir)
449 struct inode *inode = filp->f_dentry->d_inode;
455 if (filldir(dirent, ".", 1, i,
456 inode->i_ino, DT_DIR) < 0)
462 if (filldir(dirent, "..", 2, i,
463 PROC_ROOT_INO, DT_DIR) < 0)
470 switch (inode_type(inode)) {
472 size = sizeof(vx_base_stuff);
473 p = vx_base_stuff + i;
476 size = sizeof(vn_base_stuff);
477 p = vn_base_stuff + i;
482 if (i >= size/sizeof(struct vid_entry))
485 if (filldir(dirent, p->name, p->len,
486 filp->f_pos, fake_ino(inode_vid(inode),
487 p->type), p->mode >> 12) < 0)
499 /* now the upper level (virtual) */
501 static struct file_operations proc_vid_file_operations = {
502 read: generic_read_dir,
503 readdir: proc_vid_readdir,
506 static struct inode_operations proc_vid_inode_operations = {
507 lookup: proc_vid_lookup,
512 static __inline__ int atovid(const char *str, int len)
522 if (vid >= MAX_MULBY10)
533 struct dentry *proc_virtual_lookup(struct inode *dir,
534 struct dentry * dentry, struct nameidata *nd)
541 name = dentry->d_name.name;
542 len = dentry->d_name.len;
545 if (len == 7 && !memcmp(name, "current", 7)) {
546 inode = new_inode(dir->i_sb);
549 inode->i_mtime = inode->i_atime =
550 inode->i_ctime = CURRENT_TIME;
551 inode->i_ino = fake_ino(1, PROC_XID_INO);
552 inode->i_mode = S_IFLNK|S_IRWXUGO;
553 inode->i_uid = inode->i_gid = 0;
555 // inode->i_op = &proc_current_inode_operations;
556 d_add(dentry, inode);
559 if (len == 4 && !memcmp(name, "info", 4)) {
560 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_XID_INFO);
563 inode->i_fop = &proc_vid_info_file_operations;
564 PROC_I(inode)->op.proc_vid_read = proc_virtual_info;
565 inode->i_mode = S_IFREG|S_IRUGO;
566 // inode->i_size = 64;
567 // inode->i_op = &proc_current_inode_operations;
568 d_add(dentry, inode);
573 xid = atovid(name, len);
576 vxi = locate_vx_info(xid);
581 if (vx_check(xid, VX_ADMIN|VX_WATCH|VX_IDENT))
582 inode = proc_vid_make_inode(dir->i_sb,
583 vxi->vx_id, PROC_XID_INO);
587 inode->i_mode = S_IFDIR|S_IRUGO;
588 inode->i_op = &proc_vid_inode_operations;
589 inode->i_fop = &proc_vid_file_operations;
591 inode->i_flags|=S_IMMUTABLE;
593 dentry->d_op = &proc_vid_dentry_operations;
594 d_add(dentry, inode);
604 struct dentry *proc_vnet_lookup(struct inode *dir,
605 struct dentry * dentry, struct nameidata *nd)
612 name = dentry->d_name.name;
613 len = dentry->d_name.len;
615 if (len == 7 && !memcmp(name, "current", 7)) {
616 inode = new_inode(dir->i_sb);
619 inode->i_mtime = inode->i_atime =
620 inode->i_ctime = CURRENT_TIME;
621 inode->i_ino = fake_ino(1, PROC_NID_INO);
622 inode->i_mode = S_IFLNK|S_IRWXUGO;
623 inode->i_uid = inode->i_gid = 0;
625 // inode->i_op = &proc_current_inode_operations;
626 d_add(dentry, inode);
629 if (len == 4 && !memcmp(name, "info", 4)) {
630 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_NID_INFO);
633 inode->i_fop = &proc_vid_info_file_operations;
634 PROC_I(inode)->op.proc_vid_read = proc_vnet_info;
635 inode->i_mode = S_IFREG|S_IRUGO;
636 // inode->i_size = 64;
637 // inode->i_op = &proc_current_inode_operations;
638 d_add(dentry, inode);
643 nid = atovid(name, len);
646 nxi = locate_nx_info(nid);
652 inode = proc_vid_make_inode(dir->i_sb,
653 nxi->nx_id, PROC_NID_INO);
657 inode->i_mode = S_IFDIR|S_IRUGO;
658 inode->i_op = &proc_vid_inode_operations;
659 inode->i_fop = &proc_vid_file_operations;
661 inode->i_flags|=S_IMMUTABLE;
663 dentry->d_op = &proc_vid_dentry_operations;
664 d_add(dentry, inode);
676 #define PROC_NUMBUF 10
677 #define PROC_MAXVIDS 32
679 int proc_virtual_readdir(struct file * filp,
680 void * dirent, filldir_t filldir)
682 unsigned int xid_array[PROC_MAXVIDS];
683 char buf[PROC_NUMBUF];
684 unsigned int nr = filp->f_pos-3;
685 unsigned int nr_xids, i;
688 switch ((long)filp->f_pos) {
690 ino = fake_ino(0, PROC_XID_INO);
691 if (filldir(dirent, ".", 1,
692 filp->f_pos, ino, DT_DIR) < 0)
697 ino = filp->f_dentry->d_parent->d_inode->i_ino;
698 if (filldir(dirent, "..", 2,
699 filp->f_pos, ino, DT_DIR) < 0)
704 ino = fake_ino(0, PROC_XID_INFO);
705 if (filldir(dirent, "info", 4,
706 filp->f_pos, ino, DT_LNK) < 0)
711 if (current->xid > 1) {
712 ino = fake_ino(1, PROC_XID_INO);
713 if (filldir(dirent, "current", 7,
714 filp->f_pos, ino, DT_LNK) < 0)
720 nr_xids = get_xid_list(nr, xid_array, PROC_MAXVIDS);
721 for (i = 0; i < nr_xids; i++) {
722 int xid = xid_array[i];
723 ino_t ino = fake_ino(xid, PROC_XID_INO);
724 unsigned int j = PROC_NUMBUF;
726 do buf[--j] = '0' + (xid % 10); while (xid/=10);
728 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
729 filp->f_pos, ino, DT_DIR) < 0)
737 static struct file_operations proc_virtual_dir_operations = {
738 read: generic_read_dir,
739 readdir: proc_virtual_readdir,
742 static struct inode_operations proc_virtual_dir_inode_operations = {
743 lookup: proc_virtual_lookup,
747 int proc_vnet_readdir(struct file * filp,
748 void * dirent, filldir_t filldir)
750 unsigned int nid_array[PROC_MAXVIDS];
751 char buf[PROC_NUMBUF];
752 unsigned int nr = filp->f_pos-3;
753 unsigned int nr_nids, i;
756 switch ((long)filp->f_pos) {
758 ino = fake_ino(0, PROC_NID_INO);
759 if (filldir(dirent, ".", 1,
760 filp->f_pos, ino, DT_DIR) < 0)
765 ino = filp->f_dentry->d_parent->d_inode->i_ino;
766 if (filldir(dirent, "..", 2,
767 filp->f_pos, ino, DT_DIR) < 0)
772 ino = fake_ino(0, PROC_NID_INFO);
773 if (filldir(dirent, "info", 4,
774 filp->f_pos, ino, DT_LNK) < 0)
779 if (current->xid > 1) {
780 ino = fake_ino(1, PROC_NID_INO);
781 if (filldir(dirent, "current", 7,
782 filp->f_pos, ino, DT_LNK) < 0)
788 nr_nids = get_nid_list(nr, nid_array, PROC_MAXVIDS);
789 for (i = 0; i < nr_nids; i++) {
790 int nid = nid_array[i];
791 ino_t ino = fake_ino(nid, PROC_NID_INO);
792 unsigned long j = PROC_NUMBUF;
794 do buf[--j] = '0' + (nid % 10); while (nid/=10);
796 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
797 filp->f_pos, ino, DT_DIR) < 0)
805 static struct file_operations proc_vnet_dir_operations = {
806 read: generic_read_dir,
807 readdir: proc_vnet_readdir,
810 static struct inode_operations proc_vnet_dir_inode_operations = {
811 lookup: proc_vnet_lookup,
816 void proc_vx_init(void)
818 struct proc_dir_entry *ent;
820 ent = proc_mkdir("virtual", 0);
822 ent->proc_fops = &proc_virtual_dir_operations;
823 ent->proc_iops = &proc_virtual_dir_inode_operations;
827 ent = proc_mkdir("vnet", 0);
829 ent->proc_fops = &proc_vnet_dir_operations;
830 ent->proc_iops = &proc_vnet_dir_inode_operations;
841 char *task_vx_info(struct task_struct *p, char *buffer)
845 buffer += sprintf (buffer,"XID:\t%d\n", vx_task_xid(p));
846 vxi = task_get_vx_info(p);
847 if (vxi && !vx_flags(VXF_INFO_HIDE, 0)) {
848 buffer += sprintf (buffer,"BCaps:\t%016llx\n"
849 ,(unsigned long long)vxi->vx_bcaps);
850 buffer += sprintf (buffer,"CCaps:\t%016llx\n"
851 ,(unsigned long long)vxi->vx_ccaps);
852 buffer += sprintf (buffer,"CFlags:\t%016llx\n"
853 ,(unsigned long long)vxi->vx_flags);
854 buffer += sprintf (buffer,"CIPid:\t%d\n"
861 int proc_pid_vx_info(struct task_struct *p, char *buffer)
863 char * orig = buffer;
865 buffer = task_vx_info(p, buffer);
866 return buffer - orig;
869 char *task_nx_info(struct task_struct *p, char *buffer)
873 buffer += sprintf (buffer,"NID:\t%d\n", nx_task_nid(p));
874 nxi = task_get_nx_info(p);
875 if (nxi && !vx_flags(VXF_INFO_HIDE, 0)) {
878 for (i=0; i<nxi->nbipv4; i++){
879 buffer += sprintf (buffer,
880 "V4Root[%d]:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i
881 ,NIPQUAD(nxi->ipv4[i])
882 ,NIPQUAD(nxi->mask[i]));
884 buffer += sprintf (buffer,
885 "V4Root[bcast]:\t%d.%d.%d.%d\n"
886 ,NIPQUAD(nxi->v4_bcast));
892 int proc_pid_nx_info(struct task_struct *p, char *buffer)
894 char * orig = buffer;
896 buffer = task_nx_info(p, buffer);
897 return buffer - orig;