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>
26 #include <asm/uaccess.h>
27 #include <asm/unistd.h>
30 static struct proc_dir_entry *proc_virtual;
32 static struct proc_dir_entry *proc_vnet;
35 enum vid_directory_inos {
49 #define PROC_VID_MASK 0x60
52 /* first the actual feeds */
55 static int proc_virtual_info(int vid, char *buffer)
57 return sprintf(buffer,
58 "VCIVersion:\t%04x:%04x\n"
67 int proc_xid_info (int vid, char *buffer)
72 vxi = locate_vx_info(vid);
75 length = sprintf(buffer,
87 int proc_xid_status (int vid, char *buffer)
92 vxi = locate_vx_info(vid);
95 length = sprintf(buffer,
102 ,atomic_read(&vxi->vx_usecnt)
103 ,atomic_read(&vxi->vx_refcnt)
104 ,(unsigned long long)vxi->vx_flags
105 ,(unsigned long long)vxi->vx_bcaps
106 ,(unsigned long long)vxi->vx_ccaps
107 ,atomic_read(&vxi->limit.ticks)
113 int proc_xid_limit (int vid, char *buffer)
118 vxi = locate_vx_info(vid);
121 length = vx_info_proc_limit(&vxi->limit, buffer);
126 int proc_xid_sched (int vid, char *buffer)
131 vxi = locate_vx_info(vid);
134 length = vx_info_proc_sched(&vxi->sched, buffer);
139 int proc_xid_cvirt (int vid, char *buffer)
144 vxi = locate_vx_info(vid);
147 length = vx_info_proc_cvirt(&vxi->cvirt, buffer);
152 int proc_xid_cacct (int vid, char *buffer)
157 vxi = locate_vx_info(vid);
160 length = vx_info_proc_cacct(&vxi->cacct, buffer);
166 static int proc_vnet_info(int vid, char *buffer)
168 return sprintf(buffer,
169 "VCIVersion:\t%04x:%04x\n"
172 ,VCI_VERSION & 0xFFFF
178 (((a)>>0) & 0xff), (((a)>>8) & 0xff), \
179 (((a)>>16) & 0xff), (((a)>>24) & 0xff)
181 int proc_nid_info (int vid, char *buffer)
186 nxi = locate_nx_info(vid);
189 length = sprintf(buffer,
195 for (i=0; i<nxi->nbipv4; i++) {
196 length += sprintf(buffer + length,
197 "%d:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i,
198 atoquad(nxi->ipv4[i]),
199 atoquad(nxi->mask[i]));
205 int proc_nid_status (int vid, char *buffer)
210 nxi = locate_nx_info(vid);
213 length = sprintf(buffer,
216 ,atomic_read(&nxi->nx_usecnt)
217 ,atomic_read(&nxi->nx_refcnt)
223 /* here the inode helpers */
227 #define fake_ino(id,ino) (((id)<<16)|(ino))
229 #define inode_vid(i) ((i)->i_ino >> 16)
230 #define inode_type(i) ((i)->i_ino & 0xFFFF)
232 #define MAX_MULBY10 ((~0U-9)/10)
235 static struct inode *proc_vid_make_inode(struct super_block * sb,
238 struct inode *inode = new_inode(sb);
243 inode->i_mtime = inode->i_atime =
244 inode->i_ctime = CURRENT_TIME;
245 inode->i_ino = fake_ino(vid, ino);
249 // inode->i_xid = xid;
254 static int proc_vid_revalidate(struct dentry * dentry, struct nameidata *nd)
256 struct inode * inode = dentry->d_inode;
259 vid = inode_vid(inode);
260 switch (inode_type(inode) & PROC_VID_MASK) {
262 hashed = vx_info_is_hashed(vid);
265 hashed = nx_info_is_hashed(vid);
275 static int proc_vid_delete_dentry(struct dentry * dentry)
282 #define PROC_BLOCK_SIZE (PAGE_SIZE - 1024)
284 static ssize_t proc_vid_info_read(struct file * file, char * buf,
285 size_t count, loff_t *ppos)
287 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);
305 /* Static 4kB (or whatever) block capacity */
306 if (*ppos >= length) {
310 if (count + *ppos > length)
311 count = length - *ppos;
313 copy_to_user(buf, (char *) page + *ppos, count);
323 /* here comes the lower level (vid) */
325 static struct file_operations proc_vid_info_file_operations = {
326 read: proc_vid_info_read,
329 static struct dentry_operations proc_vid_dentry_operations = {
330 d_revalidate: proc_vid_revalidate,
331 // d_delete: proc_vid_delete_dentry,
342 #define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
344 static struct vid_entry vx_base_stuff[] = {
345 E(PROC_XID_INFO, "info", S_IFREG|S_IRUGO),
346 E(PROC_XID_STATUS, "status", S_IFREG|S_IRUGO),
347 E(PROC_XID_LIMIT, "limit", S_IFREG|S_IRUGO),
348 E(PROC_XID_SCHED, "sched", S_IFREG|S_IRUGO),
349 E(PROC_XID_CVIRT, "cvirt", S_IFREG|S_IRUGO),
350 E(PROC_XID_CACCT, "cacct", S_IFREG|S_IRUGO),
354 static struct vid_entry vn_base_stuff[] = {
355 E(PROC_NID_INFO, "info", S_IFREG|S_IRUGO),
356 E(PROC_NID_STATUS, "status", S_IFREG|S_IRUGO),
362 static struct dentry *proc_vid_lookup(struct inode *dir,
363 struct dentry *dentry, struct nameidata *nd)
372 switch (inode_type(dir)) {
383 for (; p->name; p++) {
384 if (p->len != dentry->d_name.len)
386 if (!memcmp(dentry->d_name.name, p->name, p->len))
393 inode = proc_vid_make_inode(dir->i_sb, inode_vid(dir), p->type);
399 PROC_I(inode)->op.proc_vid_read = proc_xid_info;
401 case PROC_XID_STATUS:
402 PROC_I(inode)->op.proc_vid_read = proc_xid_status;
405 PROC_I(inode)->op.proc_vid_read = proc_xid_limit;
408 PROC_I(inode)->op.proc_vid_read = proc_xid_sched;
411 PROC_I(inode)->op.proc_vid_read = proc_xid_cvirt;
414 PROC_I(inode)->op.proc_vid_read = proc_xid_cacct;
418 PROC_I(inode)->op.proc_vid_read = proc_nid_info;
420 case PROC_NID_STATUS:
421 PROC_I(inode)->op.proc_vid_read = proc_nid_status;
425 printk("procfs: impossible type (%d)",p->type);
427 return ERR_PTR(-EINVAL);
429 inode->i_mode = p->mode;
430 // inode->i_op = &proc_vid_info_inode_operations;
431 inode->i_fop = &proc_vid_info_file_operations;
433 inode->i_flags|=S_IMMUTABLE;
435 dentry->d_op = &proc_vid_dentry_operations;
436 d_add(dentry, inode);
439 return ERR_PTR(error);
443 static int proc_vid_readdir(struct file * filp,
444 void * dirent, filldir_t filldir)
447 struct inode *inode = filp->f_dentry->d_inode;
453 if (filldir(dirent, ".", 1, i,
454 inode->i_ino, DT_DIR) < 0)
460 if (filldir(dirent, "..", 2, i,
461 PROC_ROOT_INO, DT_DIR) < 0)
468 switch (inode_type(inode)) {
470 size = sizeof(vx_base_stuff);
471 p = vx_base_stuff + i;
474 size = sizeof(vn_base_stuff);
475 p = vn_base_stuff + i;
480 if (i >= size/sizeof(struct vid_entry))
483 if (filldir(dirent, p->name, p->len,
484 filp->f_pos, fake_ino(inode_vid(inode),
485 p->type), p->mode >> 12) < 0)
497 /* now the upper level (virtual) */
499 static struct file_operations proc_vid_file_operations = {
500 read: generic_read_dir,
501 readdir: proc_vid_readdir,
504 static struct inode_operations proc_vid_inode_operations = {
505 lookup: proc_vid_lookup,
510 static __inline__ int atovid(const char *str, int len)
520 if (vid >= MAX_MULBY10)
531 struct dentry *proc_virtual_lookup(struct inode *dir,
532 struct dentry * dentry, struct nameidata *nd)
539 name = dentry->d_name.name;
540 len = dentry->d_name.len;
543 if (len == 7 && !memcmp(name, "current", 7)) {
544 inode = new_inode(dir->i_sb);
547 inode->i_mtime = inode->i_atime =
548 inode->i_ctime = CURRENT_TIME;
549 inode->i_ino = fake_ino(1, PROC_XID_INO);
550 inode->i_mode = S_IFLNK|S_IRWXUGO;
551 inode->i_uid = inode->i_gid = 0;
553 // inode->i_op = &proc_current_inode_operations;
554 d_add(dentry, inode);
557 if (len == 4 && !memcmp(name, "info", 4)) {
558 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_XID_INFO);
561 inode->i_fop = &proc_vid_info_file_operations;
562 PROC_I(inode)->op.proc_vid_read = proc_virtual_info;
563 inode->i_mode = S_IFREG|S_IRUGO;
564 // inode->i_size = 64;
565 // inode->i_op = &proc_current_inode_operations;
566 d_add(dentry, inode);
571 xid = atovid(name, len);
574 vxi = locate_vx_info(xid);
579 if (vx_check(xid, VX_ADMIN|VX_WATCH|VX_IDENT))
580 inode = proc_vid_make_inode(dir->i_sb,
581 vxi->vx_id, PROC_XID_INO);
585 inode->i_mode = S_IFDIR|S_IRUGO;
586 inode->i_op = &proc_vid_inode_operations;
587 inode->i_fop = &proc_vid_file_operations;
589 inode->i_flags|=S_IMMUTABLE;
591 dentry->d_op = &proc_vid_dentry_operations;
592 d_add(dentry, inode);
602 struct dentry *proc_vnet_lookup(struct inode *dir,
603 struct dentry * dentry, struct nameidata *nd)
610 name = dentry->d_name.name;
611 len = dentry->d_name.len;
613 if (len == 7 && !memcmp(name, "current", 7)) {
614 inode = new_inode(dir->i_sb);
617 inode->i_mtime = inode->i_atime =
618 inode->i_ctime = CURRENT_TIME;
619 inode->i_ino = fake_ino(1, PROC_NID_INO);
620 inode->i_mode = S_IFLNK|S_IRWXUGO;
621 inode->i_uid = inode->i_gid = 0;
623 // inode->i_op = &proc_current_inode_operations;
624 d_add(dentry, inode);
627 if (len == 4 && !memcmp(name, "info", 4)) {
628 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_NID_INFO);
631 inode->i_fop = &proc_vid_info_file_operations;
632 PROC_I(inode)->op.proc_vid_read = proc_vnet_info;
633 inode->i_mode = S_IFREG|S_IRUGO;
634 // inode->i_size = 64;
635 // inode->i_op = &proc_current_inode_operations;
636 d_add(dentry, inode);
641 nid = atovid(name, len);
644 nxi = locate_nx_info(nid);
650 inode = proc_vid_make_inode(dir->i_sb,
651 nxi->nx_id, PROC_NID_INO);
655 inode->i_mode = S_IFDIR|S_IRUGO;
656 inode->i_op = &proc_vid_inode_operations;
657 inode->i_fop = &proc_vid_file_operations;
659 inode->i_flags|=S_IMMUTABLE;
661 dentry->d_op = &proc_vid_dentry_operations;
662 d_add(dentry, inode);
674 #define PROC_NUMBUF 10
675 #define PROC_MAXVIDS 32
677 int proc_virtual_readdir(struct file * filp,
678 void * dirent, filldir_t filldir)
680 unsigned int xid_array[PROC_MAXVIDS];
681 char buf[PROC_NUMBUF];
682 unsigned int nr = filp->f_pos-3;
683 unsigned int nr_xids, i;
686 switch ((long)filp->f_pos) {
688 ino = fake_ino(0, PROC_XID_INO);
689 if (filldir(dirent, ".", 1,
690 filp->f_pos, ino, DT_DIR) < 0)
695 ino = filp->f_dentry->d_parent->d_inode->i_ino;
696 if (filldir(dirent, "..", 2,
697 filp->f_pos, ino, DT_DIR) < 0)
702 ino = fake_ino(0, PROC_XID_INFO);
703 if (filldir(dirent, "info", 4,
704 filp->f_pos, ino, DT_LNK) < 0)
709 if (current->xid > 1) {
710 ino = fake_ino(1, PROC_XID_INO);
711 if (filldir(dirent, "current", 7,
712 filp->f_pos, ino, DT_LNK) < 0)
718 nr_xids = get_xid_list(nr, xid_array, PROC_MAXVIDS);
719 for (i = 0; i < nr_xids; i++) {
720 int xid = xid_array[i];
721 ino_t ino = fake_ino(xid, PROC_XID_INO);
722 unsigned int j = PROC_NUMBUF;
724 do buf[--j] = '0' + (xid % 10); while (xid/=10);
726 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
727 filp->f_pos, ino, DT_DIR) < 0)
735 static struct file_operations proc_virtual_dir_operations = {
736 read: generic_read_dir,
737 readdir: proc_virtual_readdir,
740 static struct inode_operations proc_virtual_dir_inode_operations = {
741 lookup: proc_virtual_lookup,
745 int proc_vnet_readdir(struct file * filp,
746 void * dirent, filldir_t filldir)
748 unsigned int nid_array[PROC_MAXVIDS];
749 char buf[PROC_NUMBUF];
750 unsigned int nr = filp->f_pos-3;
751 unsigned int nr_nids, i;
754 switch ((long)filp->f_pos) {
756 ino = fake_ino(0, PROC_NID_INO);
757 if (filldir(dirent, ".", 1,
758 filp->f_pos, ino, DT_DIR) < 0)
763 ino = filp->f_dentry->d_parent->d_inode->i_ino;
764 if (filldir(dirent, "..", 2,
765 filp->f_pos, ino, DT_DIR) < 0)
770 ino = fake_ino(0, PROC_NID_INFO);
771 if (filldir(dirent, "info", 4,
772 filp->f_pos, ino, DT_LNK) < 0)
777 if (current->xid > 1) {
778 ino = fake_ino(1, PROC_NID_INO);
779 if (filldir(dirent, "current", 7,
780 filp->f_pos, ino, DT_LNK) < 0)
786 nr_nids = get_nid_list(nr, nid_array, PROC_MAXVIDS);
787 for (i = 0; i < nr_nids; i++) {
788 int nid = nid_array[i];
789 ino_t ino = fake_ino(nid, PROC_NID_INO);
790 unsigned long j = PROC_NUMBUF;
792 do buf[--j] = '0' + (nid % 10); while (nid/=10);
794 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
795 filp->f_pos, ino, DT_DIR) < 0)
803 static struct file_operations proc_vnet_dir_operations = {
804 read: generic_read_dir,
805 readdir: proc_vnet_readdir,
808 static struct inode_operations proc_vnet_dir_inode_operations = {
809 lookup: proc_vnet_lookup,
814 void proc_vx_init(void)
816 struct proc_dir_entry *ent;
818 ent = proc_mkdir("virtual", 0);
820 ent->proc_fops = &proc_virtual_dir_operations;
821 ent->proc_iops = &proc_virtual_dir_inode_operations;
825 ent = proc_mkdir("vnet", 0);
827 ent->proc_fops = &proc_vnet_dir_operations;
828 ent->proc_iops = &proc_vnet_dir_inode_operations;
839 char *task_vx_info(struct task_struct *p, char *buffer)
841 return buffer + sprintf(buffer,
846 int proc_pid_vx_info(struct task_struct *p, char *buffer)
848 char * orig = buffer;
850 buffer = task_vx_info(p, buffer);
851 return buffer - orig;
854 char *task_nx_info(struct task_struct *p, char *buffer)
856 return buffer + sprintf(buffer,
861 int proc_pid_nx_info(struct task_struct *p, char *buffer)
863 char * orig = buffer;
865 buffer = task_nx_info(p, buffer);
866 return buffer - orig;