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>
23 #include <asm/uaccess.h>
24 #include <asm/unistd.h>
27 static struct proc_dir_entry *proc_virtual;
29 static struct proc_dir_entry *proc_vnet;
32 enum vid_directory_inos {
46 #define PROC_VID_MASK 0x60
49 /* first the actual feeds */
52 static int proc_virtual_info(int vid, char *buffer)
54 return sprintf(buffer,
55 "VCIVersion:\t%04x:%04x\n"
64 int proc_xid_info (int vid, char *buffer)
69 vxi = find_vx_info(vid);
72 length = sprintf(buffer,
84 int proc_xid_status (int vid, char *buffer)
89 vxi = find_vx_info(vid);
92 length = sprintf(buffer,
98 ,atomic_read(&vxi->vx_refcount)
102 ,atomic_read(&vxi->limit.ticks)
108 int proc_xid_limit (int vid, char *buffer)
113 vxi = find_vx_info(vid);
116 length = vx_info_proc_limit(&vxi->limit, buffer);
121 int proc_xid_sched (int vid, char *buffer)
126 vxi = find_vx_info(vid);
129 length = vx_info_proc_sched(&vxi->sched, buffer);
134 int proc_xid_cvirt (int vid, char *buffer)
139 vxi = find_vx_info(vid);
142 length = vx_info_proc_cvirt(&vxi->cvirt, buffer);
147 int proc_xid_cacct (int vid, char *buffer)
152 vxi = find_vx_info(vid);
155 length = vx_info_proc_cacct(&vxi->cacct, buffer);
161 static int proc_vnet_info(int vid, char *buffer)
163 return sprintf(buffer,
164 "VCIVersion:\t%04x:%04x\n"
167 ,VCI_VERSION & 0xFFFF
173 (((a)>>0) & 0xff), (((a)>>8) & 0xff), \
174 (((a)>>16) & 0xff), (((a)>>24) & 0xff)
176 int proc_nid_info (int vid, char *buffer)
181 nxi = find_nx_info(vid);
184 length = sprintf(buffer,
190 for (i=0; i<nxi->nbipv4; i++) {
191 length += sprintf(buffer + length,
192 "%d:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i,
193 atoquad(nxi->ipv4[i]),
194 atoquad(nxi->mask[i]));
200 int proc_nid_status (int vid, char *buffer)
205 nxi = find_nx_info(vid);
208 length = sprintf(buffer,
210 ,atomic_read(&nxi->nx_refcount)
216 /* here the inode helpers */
220 #define fake_ino(id,ino) (((id)<<16)|(ino))
222 #define inode_vid(i) ((i)->i_ino >> 16)
223 #define inode_type(i) ((i)->i_ino & 0xFFFF)
225 #define MAX_MULBY10 ((~0U-9)/10)
228 static struct inode *proc_vid_make_inode(struct super_block * sb,
231 struct inode *inode = new_inode(sb);
236 inode->i_mtime = inode->i_atime =
237 inode->i_ctime = CURRENT_TIME;
238 inode->i_ino = fake_ino(vid, ino);
242 // inode->i_xid = xid;
247 static int proc_vid_revalidate(struct dentry * dentry, struct nameidata *nd)
249 struct inode * inode = dentry->d_inode;
252 vid = inode_vid(inode);
253 switch (inode_type(inode) & PROC_VID_MASK) {
255 valid = vx_info_id_valid(vid);
258 valid = nx_info_id_valid(vid);
268 static int proc_vid_delete_dentry(struct dentry * dentry)
275 #define PROC_BLOCK_SIZE (PAGE_SIZE - 1024)
277 static ssize_t proc_vid_info_read(struct file * file, char * buf,
278 size_t count, loff_t *ppos)
280 struct inode * inode = file->f_dentry->d_inode;
286 if (count > PROC_BLOCK_SIZE)
287 count = PROC_BLOCK_SIZE;
288 if (!(page = __get_free_page(GFP_KERNEL)))
291 vid = inode_vid(inode);
292 length = PROC_I(inode)->op.proc_vid_read(vid, (char*)page);
298 /* Static 4kB (or whatever) block capacity */
299 if (*ppos >= length) {
303 if (count + *ppos > length)
304 count = length - *ppos;
306 copy_to_user(buf, (char *) page + *ppos, count);
316 /* here comes the lower level (vid) */
318 static struct file_operations proc_vid_info_file_operations = {
319 read: proc_vid_info_read,
322 static struct dentry_operations proc_vid_dentry_operations = {
323 d_revalidate: proc_vid_revalidate,
324 // d_delete: proc_vid_delete_dentry,
335 #define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
337 static struct vid_entry vx_base_stuff[] = {
338 E(PROC_XID_INFO, "info", S_IFREG|S_IRUGO),
339 E(PROC_XID_STATUS, "status", S_IFREG|S_IRUGO),
340 E(PROC_XID_LIMIT, "limit", S_IFREG|S_IRUGO),
341 E(PROC_XID_SCHED, "sched", S_IFREG|S_IRUGO),
342 E(PROC_XID_CVIRT, "cvirt", S_IFREG|S_IRUGO),
343 E(PROC_XID_CACCT, "cacct", S_IFREG|S_IRUGO),
347 static struct vid_entry vn_base_stuff[] = {
348 E(PROC_NID_INFO, "info", S_IFREG|S_IRUGO),
349 E(PROC_NID_STATUS, "status", S_IFREG|S_IRUGO),
355 static struct dentry *proc_vid_lookup(struct inode *dir,
356 struct dentry *dentry, struct nameidata *nd)
365 switch (inode_type(dir)) {
376 for (; p->name; p++) {
377 if (p->len != dentry->d_name.len)
379 if (!memcmp(dentry->d_name.name, p->name, p->len))
386 inode = proc_vid_make_inode(dir->i_sb, inode_vid(dir), p->type);
392 PROC_I(inode)->op.proc_vid_read = proc_xid_info;
394 case PROC_XID_STATUS:
395 PROC_I(inode)->op.proc_vid_read = proc_xid_status;
398 PROC_I(inode)->op.proc_vid_read = proc_xid_limit;
401 PROC_I(inode)->op.proc_vid_read = proc_xid_sched;
404 PROC_I(inode)->op.proc_vid_read = proc_xid_cvirt;
407 PROC_I(inode)->op.proc_vid_read = proc_xid_cacct;
411 PROC_I(inode)->op.proc_vid_read = proc_nid_info;
413 case PROC_NID_STATUS:
414 PROC_I(inode)->op.proc_vid_read = proc_nid_status;
418 printk("procfs: impossible type (%d)",p->type);
420 return ERR_PTR(-EINVAL);
422 inode->i_mode = p->mode;
423 // inode->i_op = &proc_vid_info_inode_operations;
424 inode->i_fop = &proc_vid_info_file_operations;
426 inode->i_flags|=S_IMMUTABLE;
428 dentry->d_op = &proc_vid_dentry_operations;
429 d_add(dentry, inode);
432 return ERR_PTR(error);
436 static int proc_vid_readdir(struct file * filp,
437 void * dirent, filldir_t filldir)
440 struct inode *inode = filp->f_dentry->d_inode;
446 if (filldir(dirent, ".", 1, i,
447 inode->i_ino, DT_DIR) < 0)
453 if (filldir(dirent, "..", 2, i,
454 PROC_ROOT_INO, DT_DIR) < 0)
461 switch (inode_type(inode)) {
463 size = sizeof(vx_base_stuff);
464 p = vx_base_stuff + i;
467 size = sizeof(vn_base_stuff);
468 p = vn_base_stuff + i;
473 if (i >= size/sizeof(struct vid_entry))
476 if (filldir(dirent, p->name, p->len,
477 filp->f_pos, fake_ino(inode_vid(inode),
478 p->type), p->mode >> 12) < 0)
490 /* now the upper level (virtual) */
492 static struct file_operations proc_vid_file_operations = {
493 read: generic_read_dir,
494 readdir: proc_vid_readdir,
497 static struct inode_operations proc_vid_inode_operations = {
498 lookup: proc_vid_lookup,
503 static __inline__ int atovid(const char *str, int len)
513 if (vid >= MAX_MULBY10)
524 struct dentry *proc_virtual_lookup(struct inode *dir,
525 struct dentry * dentry, struct nameidata *nd)
532 name = dentry->d_name.name;
533 len = dentry->d_name.len;
536 if (len == 7 && !memcmp(name, "current", 7)) {
537 inode = new_inode(dir->i_sb);
540 inode->i_mtime = inode->i_atime =
541 inode->i_ctime = CURRENT_TIME;
542 inode->i_ino = fake_ino(1, PROC_XID_INO);
543 inode->i_mode = S_IFLNK|S_IRWXUGO;
544 inode->i_uid = inode->i_gid = 0;
546 // inode->i_op = &proc_current_inode_operations;
547 d_add(dentry, inode);
550 if (len == 4 && !memcmp(name, "info", 4)) {
551 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_XID_INFO);
554 inode->i_fop = &proc_vid_info_file_operations;
555 PROC_I(inode)->op.proc_vid_read = proc_virtual_info;
556 inode->i_mode = S_IFREG|S_IRUGO;
557 // inode->i_size = 64;
558 // inode->i_op = &proc_current_inode_operations;
559 d_add(dentry, inode);
564 xid = atovid(name, len);
567 vxi = find_vx_info(xid);
572 if (vx_check(xid, VX_ADMIN|VX_WATCH|VX_IDENT))
573 inode = proc_vid_make_inode(dir->i_sb,
574 vxi->vx_id, PROC_XID_INO);
578 inode->i_mode = S_IFDIR|S_IRUGO;
579 inode->i_op = &proc_vid_inode_operations;
580 inode->i_fop = &proc_vid_file_operations;
582 inode->i_flags|=S_IMMUTABLE;
584 dentry->d_op = &proc_vid_dentry_operations;
585 d_add(dentry, inode);
595 struct dentry *proc_vnet_lookup(struct inode *dir,
596 struct dentry * dentry, struct nameidata *nd)
603 name = dentry->d_name.name;
604 len = dentry->d_name.len;
606 if (len == 7 && !memcmp(name, "current", 7)) {
607 inode = new_inode(dir->i_sb);
610 inode->i_mtime = inode->i_atime =
611 inode->i_ctime = CURRENT_TIME;
612 inode->i_ino = fake_ino(1, PROC_NID_INO);
613 inode->i_mode = S_IFLNK|S_IRWXUGO;
614 inode->i_uid = inode->i_gid = 0;
616 // inode->i_op = &proc_current_inode_operations;
617 d_add(dentry, inode);
620 if (len == 4 && !memcmp(name, "info", 4)) {
621 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_NID_INFO);
624 inode->i_fop = &proc_vid_info_file_operations;
625 PROC_I(inode)->op.proc_vid_read = proc_vnet_info;
626 inode->i_mode = S_IFREG|S_IRUGO;
627 // inode->i_size = 64;
628 // inode->i_op = &proc_current_inode_operations;
629 d_add(dentry, inode);
634 nid = atovid(name, len);
637 nxi = find_nx_info(nid);
643 inode = proc_vid_make_inode(dir->i_sb,
644 nxi->nx_id, PROC_NID_INO);
648 inode->i_mode = S_IFDIR|S_IRUGO;
649 inode->i_op = &proc_vid_inode_operations;
650 inode->i_fop = &proc_vid_file_operations;
652 inode->i_flags|=S_IMMUTABLE;
654 dentry->d_op = &proc_vid_dentry_operations;
655 d_add(dentry, inode);
667 #define PROC_NUMBUF 10
668 #define PROC_MAXVIDS 32
671 static int get_xid_list(int index, unsigned int *xids)
677 spin_lock(&vxlist_lock);
678 list_for_each_entry(p, &vx_infos, vx_list) {
684 if (++nr_xids >= PROC_MAXVIDS)
687 spin_unlock(&vxlist_lock);
691 int proc_virtual_readdir(struct file * filp,
692 void * dirent, filldir_t filldir)
694 unsigned int xid_array[PROC_MAXVIDS];
695 char buf[PROC_NUMBUF];
696 unsigned int nr = filp->f_pos-3;
697 unsigned int nr_xids, i;
700 switch ((long)filp->f_pos) {
702 ino = fake_ino(0, PROC_XID_INO);
703 if (filldir(dirent, ".", 1,
704 filp->f_pos, ino, DT_DIR) < 0)
709 ino = filp->f_dentry->d_parent->d_inode->i_ino;
710 if (filldir(dirent, "..", 2,
711 filp->f_pos, ino, DT_DIR) < 0)
716 ino = fake_ino(0, PROC_XID_INFO);
717 if (filldir(dirent, "info", 4,
718 filp->f_pos, ino, DT_LNK) < 0)
723 if (current->xid > 1) {
724 ino = fake_ino(1, PROC_XID_INO);
725 if (filldir(dirent, "current", 7,
726 filp->f_pos, ino, DT_LNK) < 0)
732 nr_xids = get_xid_list(nr, xid_array);
734 for (i = 0; i < nr_xids; i++) {
735 int xid = xid_array[i];
736 ino_t ino = fake_ino(xid, PROC_XID_INO);
737 unsigned long j = PROC_NUMBUF;
739 do buf[--j] = '0' + (xid % 10); while (xid/=10);
741 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
742 filp->f_pos, ino, DT_DIR) < 0)
750 static struct file_operations proc_virtual_dir_operations = {
751 read: generic_read_dir,
752 readdir: proc_virtual_readdir,
755 static struct inode_operations proc_virtual_dir_inode_operations = {
756 lookup: proc_virtual_lookup,
761 static int get_nid_list(int index, unsigned int *nids)
767 spin_lock(&nxlist_lock);
768 list_for_each_entry(p, &nx_infos, nx_list) {
774 if (++nr_nids >= PROC_MAXVIDS)
777 spin_unlock(&nxlist_lock);
781 int proc_vnet_readdir(struct file * filp,
782 void * dirent, filldir_t filldir)
784 unsigned int nid_array[PROC_MAXVIDS];
785 char buf[PROC_NUMBUF];
786 unsigned int nr = filp->f_pos-3;
787 unsigned int nr_nids, i;
790 switch ((long)filp->f_pos) {
792 ino = fake_ino(0, PROC_NID_INO);
793 if (filldir(dirent, ".", 1,
794 filp->f_pos, ino, DT_DIR) < 0)
799 ino = filp->f_dentry->d_parent->d_inode->i_ino;
800 if (filldir(dirent, "..", 2,
801 filp->f_pos, ino, DT_DIR) < 0)
806 ino = fake_ino(0, PROC_NID_INFO);
807 if (filldir(dirent, "info", 4,
808 filp->f_pos, ino, DT_LNK) < 0)
813 if (current->xid > 1) {
814 ino = fake_ino(1, PROC_NID_INO);
815 if (filldir(dirent, "current", 7,
816 filp->f_pos, ino, DT_LNK) < 0)
822 nr_nids = get_nid_list(nr, nid_array);
824 for (i = 0; i < nr_nids; i++) {
825 int nid = nid_array[i];
826 ino_t ino = fake_ino(nid, PROC_NID_INO);
827 unsigned long j = PROC_NUMBUF;
829 do buf[--j] = '0' + (nid % 10); while (nid/=10);
831 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
832 filp->f_pos, ino, DT_DIR) < 0)
840 static struct file_operations proc_vnet_dir_operations = {
841 read: generic_read_dir,
842 readdir: proc_vnet_readdir,
845 static struct inode_operations proc_vnet_dir_inode_operations = {
846 lookup: proc_vnet_lookup,
851 void proc_vx_init(void)
853 struct proc_dir_entry *ent;
855 ent = proc_mkdir("virtual", 0);
857 ent->proc_fops = &proc_virtual_dir_operations;
858 ent->proc_iops = &proc_virtual_dir_inode_operations;
862 ent = proc_mkdir("vnet", 0);
864 ent->proc_fops = &proc_vnet_dir_operations;
865 ent->proc_iops = &proc_vnet_dir_inode_operations;
876 char *task_vx_info(struct task_struct *p, char *buffer)
878 return buffer + sprintf(buffer,
883 int proc_pid_vx_info(struct task_struct *p, char *buffer)
885 char * orig = buffer;
887 buffer = task_vx_info(p, buffer);
888 return buffer - orig;
891 char *task_nx_info(struct task_struct *p, char *buffer)
893 return buffer + sprintf(buffer,
898 int proc_pid_nx_info(struct task_struct *p, char *buffer)
900 char * orig = buffer;
902 buffer = task_nx_info(p, buffer);
903 return buffer - orig;