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 = locate_vx_info(vid);
72 length = sprintf(buffer,
84 int proc_xid_status (int vid, char *buffer)
89 vxi = locate_vx_info(vid);
92 length = sprintf(buffer,
99 ,atomic_read(&vxi->vx_usecnt)
100 ,atomic_read(&vxi->vx_refcnt)
101 ,(unsigned long long)vxi->vx_flags
102 ,(unsigned long long)vxi->vx_bcaps
103 ,(unsigned long long)vxi->vx_ccaps
104 ,atomic_read(&vxi->limit.ticks)
110 int proc_xid_limit (int vid, char *buffer)
115 vxi = locate_vx_info(vid);
118 length = vx_info_proc_limit(&vxi->limit, buffer);
123 int proc_xid_sched (int vid, char *buffer)
128 vxi = locate_vx_info(vid);
131 length = vx_info_proc_sched(&vxi->sched, buffer);
136 int proc_xid_cvirt (int vid, char *buffer)
141 vxi = locate_vx_info(vid);
144 length = vx_info_proc_cvirt(&vxi->cvirt, buffer);
149 int proc_xid_cacct (int vid, char *buffer)
154 vxi = locate_vx_info(vid);
157 length = vx_info_proc_cacct(&vxi->cacct, buffer);
163 static int proc_vnet_info(int vid, char *buffer)
165 return sprintf(buffer,
166 "VCIVersion:\t%04x:%04x\n"
169 ,VCI_VERSION & 0xFFFF
175 (((a)>>0) & 0xff), (((a)>>8) & 0xff), \
176 (((a)>>16) & 0xff), (((a)>>24) & 0xff)
178 int proc_nid_info (int vid, char *buffer)
183 nxi = locate_nx_info(vid);
186 length = sprintf(buffer,
192 for (i=0; i<nxi->nbipv4; i++) {
193 length += sprintf(buffer + length,
194 "%d:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i,
195 atoquad(nxi->ipv4[i]),
196 atoquad(nxi->mask[i]));
202 int proc_nid_status (int vid, char *buffer)
207 nxi = locate_nx_info(vid);
210 length = sprintf(buffer,
213 ,atomic_read(&nxi->nx_usecnt)
214 ,atomic_read(&nxi->nx_refcnt)
220 /* here the inode helpers */
224 #define fake_ino(id,ino) (((id)<<16)|(ino))
226 #define inode_vid(i) ((i)->i_ino >> 16)
227 #define inode_type(i) ((i)->i_ino & 0xFFFF)
229 #define MAX_MULBY10 ((~0U-9)/10)
232 static struct inode *proc_vid_make_inode(struct super_block * sb,
235 struct inode *inode = new_inode(sb);
240 inode->i_mtime = inode->i_atime =
241 inode->i_ctime = CURRENT_TIME;
242 inode->i_ino = fake_ino(vid, ino);
246 // inode->i_xid = xid;
251 static int proc_vid_revalidate(struct dentry * dentry, struct nameidata *nd)
253 struct inode * inode = dentry->d_inode;
256 vid = inode_vid(inode);
257 switch (inode_type(inode) & PROC_VID_MASK) {
259 hashed = vx_info_is_hashed(vid);
262 hashed = nx_info_is_hashed(vid);
272 static int proc_vid_delete_dentry(struct dentry * dentry)
279 #define PROC_BLOCK_SIZE (PAGE_SIZE - 1024)
281 static ssize_t proc_vid_info_read(struct file * file, char * buf,
282 size_t count, loff_t *ppos)
284 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);
302 /* Static 4kB (or whatever) block capacity */
303 if (*ppos >= length) {
307 if (count + *ppos > length)
308 count = length - *ppos;
310 copy_to_user(buf, (char *) page + *ppos, count);
320 /* here comes the lower level (vid) */
322 static struct file_operations proc_vid_info_file_operations = {
323 read: proc_vid_info_read,
326 static struct dentry_operations proc_vid_dentry_operations = {
327 d_revalidate: proc_vid_revalidate,
328 // d_delete: proc_vid_delete_dentry,
339 #define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
341 static struct vid_entry vx_base_stuff[] = {
342 E(PROC_XID_INFO, "info", S_IFREG|S_IRUGO),
343 E(PROC_XID_STATUS, "status", S_IFREG|S_IRUGO),
344 E(PROC_XID_LIMIT, "limit", S_IFREG|S_IRUGO),
345 E(PROC_XID_SCHED, "sched", S_IFREG|S_IRUGO),
346 E(PROC_XID_CVIRT, "cvirt", S_IFREG|S_IRUGO),
347 E(PROC_XID_CACCT, "cacct", S_IFREG|S_IRUGO),
351 static struct vid_entry vn_base_stuff[] = {
352 E(PROC_NID_INFO, "info", S_IFREG|S_IRUGO),
353 E(PROC_NID_STATUS, "status", S_IFREG|S_IRUGO),
359 static struct dentry *proc_vid_lookup(struct inode *dir,
360 struct dentry *dentry, struct nameidata *nd)
369 switch (inode_type(dir)) {
380 for (; p->name; p++) {
381 if (p->len != dentry->d_name.len)
383 if (!memcmp(dentry->d_name.name, p->name, p->len))
390 inode = proc_vid_make_inode(dir->i_sb, inode_vid(dir), p->type);
396 PROC_I(inode)->op.proc_vid_read = proc_xid_info;
398 case PROC_XID_STATUS:
399 PROC_I(inode)->op.proc_vid_read = proc_xid_status;
402 PROC_I(inode)->op.proc_vid_read = proc_xid_limit;
405 PROC_I(inode)->op.proc_vid_read = proc_xid_sched;
408 PROC_I(inode)->op.proc_vid_read = proc_xid_cvirt;
411 PROC_I(inode)->op.proc_vid_read = proc_xid_cacct;
415 PROC_I(inode)->op.proc_vid_read = proc_nid_info;
417 case PROC_NID_STATUS:
418 PROC_I(inode)->op.proc_vid_read = proc_nid_status;
422 printk("procfs: impossible type (%d)",p->type);
424 return ERR_PTR(-EINVAL);
426 inode->i_mode = p->mode;
427 // inode->i_op = &proc_vid_info_inode_operations;
428 inode->i_fop = &proc_vid_info_file_operations;
430 inode->i_flags|=S_IMMUTABLE;
432 dentry->d_op = &proc_vid_dentry_operations;
433 d_add(dentry, inode);
436 return ERR_PTR(error);
440 static int proc_vid_readdir(struct file * filp,
441 void * dirent, filldir_t filldir)
444 struct inode *inode = filp->f_dentry->d_inode;
450 if (filldir(dirent, ".", 1, i,
451 inode->i_ino, DT_DIR) < 0)
457 if (filldir(dirent, "..", 2, i,
458 PROC_ROOT_INO, DT_DIR) < 0)
465 switch (inode_type(inode)) {
467 size = sizeof(vx_base_stuff);
468 p = vx_base_stuff + i;
471 size = sizeof(vn_base_stuff);
472 p = vn_base_stuff + i;
477 if (i >= size/sizeof(struct vid_entry))
480 if (filldir(dirent, p->name, p->len,
481 filp->f_pos, fake_ino(inode_vid(inode),
482 p->type), p->mode >> 12) < 0)
494 /* now the upper level (virtual) */
496 static struct file_operations proc_vid_file_operations = {
497 read: generic_read_dir,
498 readdir: proc_vid_readdir,
501 static struct inode_operations proc_vid_inode_operations = {
502 lookup: proc_vid_lookup,
507 static __inline__ int atovid(const char *str, int len)
517 if (vid >= MAX_MULBY10)
528 struct dentry *proc_virtual_lookup(struct inode *dir,
529 struct dentry * dentry, struct nameidata *nd)
536 name = dentry->d_name.name;
537 len = dentry->d_name.len;
540 if (len == 7 && !memcmp(name, "current", 7)) {
541 inode = new_inode(dir->i_sb);
544 inode->i_mtime = inode->i_atime =
545 inode->i_ctime = CURRENT_TIME;
546 inode->i_ino = fake_ino(1, PROC_XID_INO);
547 inode->i_mode = S_IFLNK|S_IRWXUGO;
548 inode->i_uid = inode->i_gid = 0;
550 // inode->i_op = &proc_current_inode_operations;
551 d_add(dentry, inode);
554 if (len == 4 && !memcmp(name, "info", 4)) {
555 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_XID_INFO);
558 inode->i_fop = &proc_vid_info_file_operations;
559 PROC_I(inode)->op.proc_vid_read = proc_virtual_info;
560 inode->i_mode = S_IFREG|S_IRUGO;
561 // inode->i_size = 64;
562 // inode->i_op = &proc_current_inode_operations;
563 d_add(dentry, inode);
568 xid = atovid(name, len);
571 vxi = locate_vx_info(xid);
576 if (vx_check(xid, VX_ADMIN|VX_WATCH|VX_IDENT))
577 inode = proc_vid_make_inode(dir->i_sb,
578 vxi->vx_id, PROC_XID_INO);
582 inode->i_mode = S_IFDIR|S_IRUGO;
583 inode->i_op = &proc_vid_inode_operations;
584 inode->i_fop = &proc_vid_file_operations;
586 inode->i_flags|=S_IMMUTABLE;
588 dentry->d_op = &proc_vid_dentry_operations;
589 d_add(dentry, inode);
599 struct dentry *proc_vnet_lookup(struct inode *dir,
600 struct dentry * dentry, struct nameidata *nd)
607 name = dentry->d_name.name;
608 len = dentry->d_name.len;
610 if (len == 7 && !memcmp(name, "current", 7)) {
611 inode = new_inode(dir->i_sb);
614 inode->i_mtime = inode->i_atime =
615 inode->i_ctime = CURRENT_TIME;
616 inode->i_ino = fake_ino(1, PROC_NID_INO);
617 inode->i_mode = S_IFLNK|S_IRWXUGO;
618 inode->i_uid = inode->i_gid = 0;
620 // inode->i_op = &proc_current_inode_operations;
621 d_add(dentry, inode);
624 if (len == 4 && !memcmp(name, "info", 4)) {
625 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_NID_INFO);
628 inode->i_fop = &proc_vid_info_file_operations;
629 PROC_I(inode)->op.proc_vid_read = proc_vnet_info;
630 inode->i_mode = S_IFREG|S_IRUGO;
631 // inode->i_size = 64;
632 // inode->i_op = &proc_current_inode_operations;
633 d_add(dentry, inode);
638 nid = atovid(name, len);
641 nxi = locate_nx_info(nid);
647 inode = proc_vid_make_inode(dir->i_sb,
648 nxi->nx_id, PROC_NID_INO);
652 inode->i_mode = S_IFDIR|S_IRUGO;
653 inode->i_op = &proc_vid_inode_operations;
654 inode->i_fop = &proc_vid_file_operations;
656 inode->i_flags|=S_IMMUTABLE;
658 dentry->d_op = &proc_vid_dentry_operations;
659 d_add(dentry, inode);
671 #define PROC_NUMBUF 10
672 #define PROC_MAXVIDS 32
674 int proc_virtual_readdir(struct file * filp,
675 void * dirent, filldir_t filldir)
677 unsigned int xid_array[PROC_MAXVIDS];
678 char buf[PROC_NUMBUF];
679 unsigned int nr = filp->f_pos-3;
680 unsigned int nr_xids, i;
683 switch ((long)filp->f_pos) {
685 ino = fake_ino(0, PROC_XID_INO);
686 if (filldir(dirent, ".", 1,
687 filp->f_pos, ino, DT_DIR) < 0)
692 ino = filp->f_dentry->d_parent->d_inode->i_ino;
693 if (filldir(dirent, "..", 2,
694 filp->f_pos, ino, DT_DIR) < 0)
699 ino = fake_ino(0, PROC_XID_INFO);
700 if (filldir(dirent, "info", 4,
701 filp->f_pos, ino, DT_LNK) < 0)
706 if (current->xid > 1) {
707 ino = fake_ino(1, PROC_XID_INO);
708 if (filldir(dirent, "current", 7,
709 filp->f_pos, ino, DT_LNK) < 0)
715 nr_xids = get_xid_list(nr, xid_array, PROC_MAXVIDS);
716 for (i = 0; i < nr_xids; i++) {
717 int xid = xid_array[i];
718 ino_t ino = fake_ino(xid, PROC_XID_INO);
719 unsigned int j = PROC_NUMBUF;
721 do buf[--j] = '0' + (xid % 10); while (xid/=10);
723 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
724 filp->f_pos, ino, DT_DIR) < 0)
732 static struct file_operations proc_virtual_dir_operations = {
733 read: generic_read_dir,
734 readdir: proc_virtual_readdir,
737 static struct inode_operations proc_virtual_dir_inode_operations = {
738 lookup: proc_virtual_lookup,
742 int proc_vnet_readdir(struct file * filp,
743 void * dirent, filldir_t filldir)
745 unsigned int nid_array[PROC_MAXVIDS];
746 char buf[PROC_NUMBUF];
747 unsigned int nr = filp->f_pos-3;
748 unsigned int nr_nids, i;
751 switch ((long)filp->f_pos) {
753 ino = fake_ino(0, PROC_NID_INO);
754 if (filldir(dirent, ".", 1,
755 filp->f_pos, ino, DT_DIR) < 0)
760 ino = filp->f_dentry->d_parent->d_inode->i_ino;
761 if (filldir(dirent, "..", 2,
762 filp->f_pos, ino, DT_DIR) < 0)
767 ino = fake_ino(0, PROC_NID_INFO);
768 if (filldir(dirent, "info", 4,
769 filp->f_pos, ino, DT_LNK) < 0)
774 if (current->xid > 1) {
775 ino = fake_ino(1, PROC_NID_INO);
776 if (filldir(dirent, "current", 7,
777 filp->f_pos, ino, DT_LNK) < 0)
783 nr_nids = get_nid_list(nr, nid_array, PROC_MAXVIDS);
784 for (i = 0; i < nr_nids; i++) {
785 int nid = nid_array[i];
786 ino_t ino = fake_ino(nid, PROC_NID_INO);
787 unsigned long j = PROC_NUMBUF;
789 do buf[--j] = '0' + (nid % 10); while (nid/=10);
791 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
792 filp->f_pos, ino, DT_DIR) < 0)
800 static struct file_operations proc_vnet_dir_operations = {
801 read: generic_read_dir,
802 readdir: proc_vnet_readdir,
805 static struct inode_operations proc_vnet_dir_inode_operations = {
806 lookup: proc_vnet_lookup,
811 void proc_vx_init(void)
813 struct proc_dir_entry *ent;
815 ent = proc_mkdir("virtual", 0);
817 ent->proc_fops = &proc_virtual_dir_operations;
818 ent->proc_iops = &proc_virtual_dir_inode_operations;
822 ent = proc_mkdir("vnet", 0);
824 ent->proc_fops = &proc_vnet_dir_operations;
825 ent->proc_iops = &proc_vnet_dir_inode_operations;
836 char *task_vx_info(struct task_struct *p, char *buffer)
838 return buffer + sprintf(buffer,
843 int proc_pid_vx_info(struct task_struct *p, char *buffer)
845 char * orig = buffer;
847 buffer = task_vx_info(p, buffer);
848 return buffer - orig;
851 char *task_nx_info(struct task_struct *p, char *buffer)
853 return buffer + sprintf(buffer,
858 int proc_pid_nx_info(struct task_struct *p, char *buffer)
860 char * orig = buffer;
862 buffer = task_nx_info(p, buffer);
863 return buffer - orig;