2 * linux/kernel/vserver/proc.c
4 * Virtual Context Support
6 * Copyright (C) 2003-2007 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
15 * V0.08 remove inode type
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>
27 #include <linux/vserver/global.h>
29 #include <asm/uaccess.h>
30 #include <asm/unistd.h>
32 #include "cvirt_proc.h"
33 #include "cacct_proc.h"
34 #include "limit_proc.h"
35 #include "sched_proc.h"
36 #include "vci_config.h"
38 static struct proc_dir_entry *proc_virtual;
40 static struct proc_dir_entry *proc_virtnet;
43 /* first the actual feeds */
46 static int proc_vci(char *buffer)
48 return sprintf(buffer,
49 "VCIVersion:\t%04x:%04x\n"
59 static int proc_virtual_info(char *buffer)
61 return proc_vci(buffer);
64 static int proc_virtual_status(char *buffer)
66 return sprintf(buffer,
69 "#NSProxy:\t%d\t%d %d %d %d\n"
70 ,atomic_read(&vx_global_ctotal)
71 ,atomic_read(&vx_global_cactive)
72 ,atomic_read(&vs_global_nsproxy)
73 ,atomic_read(&vs_global_fs)
74 ,atomic_read(&vs_global_mnt_ns)
75 ,atomic_read(&vs_global_uts_ns)
76 ,atomic_read(&vs_global_ipc_ns)
81 int proc_vxi_info (struct vx_info *vxi, char *buffer)
85 length = sprintf(buffer,
96 int proc_vxi_status (struct vx_info *vxi, char *buffer)
100 length = sprintf(buffer,
107 ,atomic_read(&vxi->vx_usecnt)
108 ,atomic_read(&vxi->vx_tasks)
109 ,(unsigned long long)vxi->vx_flags
110 ,(unsigned long long)vxi->vx_bcaps
111 ,(unsigned long long)vxi->vx_ccaps
117 int proc_vxi_limit (struct vx_info *vxi, char *buffer)
119 return vx_info_proc_limit(&vxi->limit, buffer);
122 int proc_vxi_sched (struct vx_info *vxi, char *buffer)
126 length = vx_info_proc_sched(&vxi->sched, buffer);
127 for_each_online_cpu(cpu) {
128 length += vx_info_proc_sched_pc(
129 &vx_per_cpu(vxi, sched_pc, cpu),
130 buffer + length, cpu);
135 int proc_vxi_nsproxy (struct vx_info *vxi, char *buffer)
137 return vx_info_proc_nsproxy(vxi->vx_nsproxy, buffer);
140 int proc_vxi_cvirt (struct vx_info *vxi, char *buffer)
145 length = vx_info_proc_cvirt(&vxi->cvirt, buffer);
146 for_each_online_cpu(cpu) {
147 length += vx_info_proc_cvirt_pc(
148 &vx_per_cpu(vxi, cvirt_pc, cpu),
149 buffer + length, cpu);
154 int proc_vxi_cacct (struct vx_info *vxi, char *buffer)
156 return vx_info_proc_cacct(&vxi->cacct, buffer);
160 static int proc_virtnet_info(char *buffer)
162 return proc_vci(buffer);
165 static int proc_virtnet_status(char *buffer)
167 return sprintf(buffer,
170 ,atomic_read(&nx_global_ctotal)
171 ,atomic_read(&nx_global_cactive)
175 int proc_nxi_info (struct nx_info *nxi, char *buffer)
179 length = sprintf(buffer,
185 for (i=0; i<nxi->nbipv4; i++) {
186 length += sprintf(buffer + length,
187 "%d:\t" NIPQUAD_FMT "/" NIPQUAD_FMT "\n", i,
188 NIPQUAD(nxi->ipv4[i]), NIPQUAD(nxi->mask[i]));
190 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
191 for (i=0; i<nxi->nbipv6;i++) {
192 length += sprintf(buffer + length,
193 "%d:\t" NIP6_FMT "/%d\n", i,
194 NIP6(nxi->ipv6[i]), nxi->prefix6[i]);
196 #endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */
200 int proc_nxi_status (struct nx_info *nxi, char *buffer)
204 length = sprintf(buffer,
209 ,atomic_read(&nxi->nx_usecnt)
210 ,atomic_read(&nxi->nx_tasks)
211 ,(unsigned long long)nxi->nx_flags
212 ,(unsigned long long)nxi->nx_ncaps
219 /* here the inode helpers */
225 struct inode_operations *iop;
226 struct file_operations *fop;
230 static struct inode *vs_proc_make_inode(struct super_block *sb, struct vs_entry *p)
232 struct inode *inode = new_inode(sb);
237 inode->i_mode = p->mode;
239 inode->i_op = p->iop;
241 inode->i_fop = p->fop;
243 inode->i_nlink = (p->mode & S_IFDIR) ? 2 : 1;
244 inode->i_flags |= S_IMMUTABLE;
246 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
255 static struct dentry *vs_proc_instantiate(struct inode *dir,
256 struct dentry *dentry, int id, void *ptr)
258 struct vs_entry *p = ptr;
259 struct inode *inode = vs_proc_make_inode(dir->i_sb, p);
260 struct dentry *error = ERR_PTR(-EINVAL);
265 PROC_I(inode)->op = p->op;
266 PROC_I(inode)->fd = id;
267 d_add(dentry, inode);
275 typedef struct dentry *instantiate_t(struct inode *, struct dentry *, int, void *);
278 * Fill a directory entry.
280 * If possible create the dcache entry and derive our inode number and
281 * file type from dcache entry.
283 * Since all of the proc inode numbers are dynamically generated, the inode
284 * numbers do not exist until the inode is cache. This means creating the
285 * the dcache entry in readdir is necessary to keep the inode numbers
286 * reported by readdir in sync with the inode numbers reported
289 static int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
290 char *name, int len, instantiate_t instantiate, int id, void *ptr)
292 struct dentry *child, *dir = filp->f_dentry;
296 unsigned type = DT_UNKNOWN;
300 qname.hash = full_name_hash(name, len);
302 child = d_lookup(dir, &qname);
305 new = d_alloc(dir, &qname);
307 child = instantiate(dir->d_inode, new, id, ptr);
314 if (!child || IS_ERR(child) || !child->d_inode)
315 goto end_instantiate;
316 inode = child->d_inode;
319 type = inode->i_mode >> 12;
324 ino = find_inode_number(dir, &qname);
327 return filldir(dirent, name, len, filp->f_pos, ino, type);
332 /* get and revalidate vx_info/xid */
335 struct vx_info *get_proc_vx_info(struct inode *inode)
337 return lookup_vx_info(PROC_I(inode)->fd);
340 static int proc_xid_revalidate(struct dentry * dentry, struct nameidata *nd)
342 struct inode *inode = dentry->d_inode;
343 xid_t xid = PROC_I(inode)->fd;
345 if (!xid || xid_is_hashed(xid))
352 /* get and revalidate nx_info/nid */
354 static int proc_nid_revalidate(struct dentry * dentry, struct nameidata *nd)
356 struct inode *inode = dentry->d_inode;
357 nid_t nid = PROC_I(inode)->fd;
359 if (!nid || nid_is_hashed(nid))
367 #define PROC_BLOCK_SIZE (PAGE_SIZE - 1024)
369 static ssize_t proc_vs_info_read(struct file * file, char __user * buf,
370 size_t count, loff_t *ppos)
372 struct inode *inode = file->f_dentry->d_inode;
376 if (count > PROC_BLOCK_SIZE)
377 count = PROC_BLOCK_SIZE;
379 /* fade that out as soon as stable */
380 WARN_ON(PROC_I(inode)->fd);
382 if (!(page = __get_free_page(GFP_KERNEL)))
385 BUG_ON(!PROC_I(inode)->op.proc_vs_read);
386 length = PROC_I(inode)->op.proc_vs_read((char*)page);
389 length = simple_read_from_buffer(buf, count, ppos,
390 (char *)page, length);
396 static ssize_t proc_vx_info_read(struct file * file, char __user * buf,
397 size_t count, loff_t *ppos)
399 struct inode *inode = file->f_dentry->d_inode;
400 struct vx_info *vxi = NULL;
401 xid_t xid = PROC_I(inode)->fd;
405 if (count > PROC_BLOCK_SIZE)
406 count = PROC_BLOCK_SIZE;
408 /* fade that out as soon as stable */
410 vxi = lookup_vx_info(xid);
415 if (!(page = __get_free_page(GFP_KERNEL)))
418 BUG_ON(!PROC_I(inode)->op.proc_vxi_read);
419 length = PROC_I(inode)->op.proc_vxi_read(vxi, (char*)page);
422 length = simple_read_from_buffer(buf, count, ppos,
423 (char *)page, length);
432 static ssize_t proc_nx_info_read(struct file * file, char __user * buf,
433 size_t count, loff_t *ppos)
435 struct inode *inode = file->f_dentry->d_inode;
436 struct nx_info *nxi = NULL;
437 nid_t nid = PROC_I(inode)->fd;
441 if (count > PROC_BLOCK_SIZE)
442 count = PROC_BLOCK_SIZE;
444 /* fade that out as soon as stable */
446 nxi = lookup_nx_info(nid);
451 if (!(page = __get_free_page(GFP_KERNEL)))
454 BUG_ON(!PROC_I(inode)->op.proc_nxi_read);
455 length = PROC_I(inode)->op.proc_nxi_read(nxi, (char*)page);
458 length = simple_read_from_buffer(buf, count, ppos,
459 (char *)page, length);
470 /* here comes the lower level */
473 #define NOD(NAME, MODE, IOP, FOP, OP) { \
474 .len = sizeof(NAME) - 1, \
483 #define DIR(NAME, MODE, OTYPE) \
484 NOD(NAME, (S_IFDIR|(MODE)), \
485 &proc_##OTYPE##_inode_operations, \
486 &proc_##OTYPE##_file_operations, { } )
488 #define INF(NAME, MODE, OTYPE) \
489 NOD(NAME, (S_IFREG|(MODE)), NULL, \
490 &proc_vs_info_file_operations, \
491 { .proc_vs_read = &proc_##OTYPE } )
493 #define VINF(NAME, MODE, OTYPE) \
494 NOD(NAME, (S_IFREG|(MODE)), NULL, \
495 &proc_vx_info_file_operations, \
496 { .proc_vxi_read = &proc_##OTYPE } )
498 #define NINF(NAME, MODE, OTYPE) \
499 NOD(NAME, (S_IFREG|(MODE)), NULL, \
500 &proc_nx_info_file_operations, \
501 { .proc_nxi_read = &proc_##OTYPE } )
504 static struct file_operations proc_vs_info_file_operations = {
505 .read = proc_vs_info_read,
508 static struct file_operations proc_vx_info_file_operations = {
509 .read = proc_vx_info_read,
512 static struct dentry_operations proc_xid_dentry_operations = {
513 .d_revalidate = proc_xid_revalidate,
516 static struct vs_entry vx_base_stuff[] = {
517 VINF("info", S_IRUGO, vxi_info),
518 VINF("status", S_IRUGO, vxi_status),
519 VINF("limit", S_IRUGO, vxi_limit),
520 VINF("sched", S_IRUGO, vxi_sched),
521 VINF("nsproxy", S_IRUGO, vxi_nsproxy),
522 VINF("cvirt", S_IRUGO, vxi_cvirt),
523 VINF("cacct", S_IRUGO, vxi_cacct),
530 static struct dentry *proc_xid_instantiate(struct inode *dir,
531 struct dentry *dentry, int id, void *ptr)
533 dentry->d_op = &proc_xid_dentry_operations;
534 return vs_proc_instantiate(dir, dentry, id, ptr);
537 static struct dentry *proc_xid_lookup(struct inode *dir,
538 struct dentry *dentry, struct nameidata *nd)
540 struct vs_entry *p = vx_base_stuff;
541 struct dentry *error = ERR_PTR(-ENOENT);
543 for (; p->name; p++) {
544 if (p->len != dentry->d_name.len)
546 if (!memcmp(dentry->d_name.name, p->name, p->len))
552 error = proc_xid_instantiate(dir, dentry, PROC_I(dir)->fd, p);
557 static int proc_xid_readdir(struct file * filp,
558 void * dirent, filldir_t filldir)
560 struct dentry *dentry = filp->f_dentry;
561 struct inode *inode = dentry->d_inode;
562 struct vs_entry *p = vx_base_stuff;
563 int size = sizeof(vx_base_stuff)/sizeof(struct vs_entry);
571 if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0)
576 ino = parent_ino(dentry);
577 if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0)
585 for (p += index; p->name; p++) {
586 if (proc_fill_cache(filp, dirent, filldir, p->name, p->len,
587 vs_proc_instantiate, PROC_I(inode)->fd, p))
599 static struct file_operations proc_nx_info_file_operations = {
600 .read = proc_nx_info_read,
603 static struct dentry_operations proc_nid_dentry_operations = {
604 .d_revalidate = proc_nid_revalidate,
607 static struct vs_entry nx_base_stuff[] = {
608 NINF("info", S_IRUGO, nxi_info),
609 NINF("status", S_IRUGO, nxi_status),
614 static struct dentry *proc_nid_instantiate(struct inode *dir,
615 struct dentry *dentry, int id, void *ptr)
617 dentry->d_op = &proc_nid_dentry_operations;
618 return vs_proc_instantiate(dir, dentry, id, ptr);
621 static struct dentry *proc_nid_lookup(struct inode *dir,
622 struct dentry *dentry, struct nameidata *nd)
624 struct vs_entry *p = nx_base_stuff;
625 struct dentry *error = ERR_PTR(-ENOENT);
627 for (; p->name; p++) {
628 if (p->len != dentry->d_name.len)
630 if (!memcmp(dentry->d_name.name, p->name, p->len))
636 error = proc_nid_instantiate(dir, dentry, PROC_I(dir)->fd, p);
641 static int proc_nid_readdir(struct file * filp,
642 void * dirent, filldir_t filldir)
644 struct dentry *dentry = filp->f_dentry;
645 struct inode *inode = dentry->d_inode;
646 struct vs_entry *p = nx_base_stuff;
647 int size = sizeof(nx_base_stuff)/sizeof(struct vs_entry);
655 if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0)
660 ino = parent_ino(dentry);
661 if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0)
669 for (p += index; p->name; p++) {
670 if (proc_fill_cache(filp, dirent, filldir, p->name, p->len,
671 vs_proc_instantiate, PROC_I(inode)->fd, p))
682 #define MAX_MULBY10 ((~0U-9)/10)
684 static inline int atovid(const char *str, int len)
694 if (vid >= MAX_MULBY10)
704 /* now the upper level (virtual) */
707 static struct file_operations proc_xid_file_operations = {
708 .read = generic_read_dir,
709 .readdir = proc_xid_readdir,
712 static struct inode_operations proc_xid_inode_operations = {
713 .lookup = proc_xid_lookup,
716 static struct vs_entry vx_virtual_stuff[] = {
717 INF("info", S_IRUGO, virtual_info),
718 INF("status", S_IRUGO, virtual_status),
719 DIR(NULL, S_IRUGO|S_IXUGO, xid),
723 static struct dentry *proc_virtual_lookup(struct inode *dir,
724 struct dentry *dentry, struct nameidata *nd)
726 struct vs_entry *p = vx_virtual_stuff;
727 struct dentry *error = ERR_PTR(-ENOENT);
730 for (; p->name; p++) {
731 if (p->len != dentry->d_name.len)
733 if (!memcmp(dentry->d_name.name, p->name, p->len))
739 id = atovid(dentry->d_name.name, dentry->d_name.len);
740 if ((id < 0) || !xid_is_hashed(id))
744 error = proc_xid_instantiate(dir, dentry, id, p);
749 static struct file_operations proc_nid_file_operations = {
750 .read = generic_read_dir,
751 .readdir = proc_nid_readdir,
754 static struct inode_operations proc_nid_inode_operations = {
755 .lookup = proc_nid_lookup,
758 static struct vs_entry nx_virtnet_stuff[] = {
759 INF("info", S_IRUGO, virtnet_info),
760 INF("status", S_IRUGO, virtnet_status),
761 DIR(NULL, S_IRUGO|S_IXUGO, nid),
765 static struct dentry *proc_virtnet_lookup(struct inode *dir,
766 struct dentry *dentry, struct nameidata *nd)
768 struct vs_entry *p = nx_virtnet_stuff;
769 struct dentry *error = ERR_PTR(-ENOENT);
772 for (; p->name; p++) {
773 if (p->len != dentry->d_name.len)
775 if (!memcmp(dentry->d_name.name, p->name, p->len))
781 id = atovid(dentry->d_name.name, dentry->d_name.len);
782 if ((id < 0) || !nid_is_hashed(id))
786 error = proc_nid_instantiate(dir, dentry, id, p);
793 #define PROC_NUMBUF 10
794 #define PROC_MAXVIDS 32
796 int proc_virtual_readdir(struct file * filp,
797 void * dirent, filldir_t filldir)
799 struct dentry *dentry = filp->f_dentry;
800 struct inode *inode = dentry->d_inode;
801 struct vs_entry *p = vx_virtual_stuff;
802 int size = sizeof(vx_virtual_stuff)/sizeof(struct vs_entry);
804 unsigned int xid_array[PROC_MAXVIDS];
805 char buf[PROC_NUMBUF];
806 unsigned int nr_xids, i;
813 if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0)
818 ino = parent_ino(dentry);
819 if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0)
827 for (p += index; p->name; p++) {
828 if (proc_fill_cache(filp, dirent, filldir, p->name, p->len,
829 vs_proc_instantiate, 0, p))
835 p = &vx_virtual_stuff[size-1];
836 nr_xids = get_xid_list(index, xid_array, PROC_MAXVIDS);
837 for (i = 0; i < nr_xids; i++) {
838 int n, xid = xid_array[i];
839 unsigned int j = PROC_NUMBUF;
842 do buf[--j] = '0' + (n % 10); while (n /= 10);
844 if (proc_fill_cache(filp, dirent, filldir, buf+j, PROC_NUMBUF-j,
845 vs_proc_instantiate, xid, p))
855 static int proc_virtual_getattr(struct vfsmount *mnt,
856 struct dentry *dentry, struct kstat *stat)
858 struct inode *inode = dentry->d_inode;
860 generic_fillattr(inode, stat);
861 stat->nlink = 2 + atomic_read(&vx_global_cactive);
865 static struct file_operations proc_virtual_dir_operations = {
866 .read = generic_read_dir,
867 .readdir = proc_virtual_readdir,
870 static struct inode_operations proc_virtual_dir_inode_operations = {
871 .getattr = proc_virtual_getattr,
872 .lookup = proc_virtual_lookup,
879 int proc_virtnet_readdir(struct file * filp,
880 void * dirent, filldir_t filldir)
882 struct dentry *dentry = filp->f_dentry;
883 struct inode *inode = dentry->d_inode;
884 struct vs_entry *p = nx_virtnet_stuff;
885 int size = sizeof(nx_virtnet_stuff)/sizeof(struct vs_entry);
887 unsigned int nid_array[PROC_MAXVIDS];
888 char buf[PROC_NUMBUF];
889 unsigned int nr_nids, i;
896 if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0)
901 ino = parent_ino(dentry);
902 if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0)
910 for (p += index; p->name; p++) {
911 if (proc_fill_cache(filp, dirent, filldir, p->name, p->len,
912 vs_proc_instantiate, 0, p))
918 p = &nx_virtnet_stuff[size-1];
919 nr_nids = get_nid_list(index, nid_array, PROC_MAXVIDS);
920 for (i = 0; i < nr_nids; i++) {
921 int n, nid = nid_array[i];
922 unsigned int j = PROC_NUMBUF;
925 do buf[--j] = '0' + (n % 10); while (n /= 10);
927 if (proc_fill_cache(filp, dirent, filldir, buf+j, PROC_NUMBUF-j,
928 vs_proc_instantiate, nid, p))
938 static int proc_virtnet_getattr(struct vfsmount *mnt,
939 struct dentry *dentry, struct kstat *stat)
941 struct inode *inode = dentry->d_inode;
943 generic_fillattr(inode, stat);
944 stat->nlink = 2 + atomic_read(&nx_global_cactive);
948 static struct file_operations proc_virtnet_dir_operations = {
949 .read = generic_read_dir,
950 .readdir = proc_virtnet_readdir,
953 static struct inode_operations proc_virtnet_dir_inode_operations = {
954 .getattr = proc_virtnet_getattr,
955 .lookup = proc_virtnet_lookup,
960 void proc_vx_init(void)
962 struct proc_dir_entry *ent;
964 ent = proc_mkdir("virtual", 0);
966 ent->proc_fops = &proc_virtual_dir_operations;
967 ent->proc_iops = &proc_virtual_dir_inode_operations;
971 ent = proc_mkdir("virtnet", 0);
973 ent->proc_fops = &proc_virtnet_dir_operations;
974 ent->proc_iops = &proc_virtnet_dir_inode_operations;
985 int proc_pid_vx_info(struct task_struct *p, char *buffer)
988 char * orig = buffer;
990 buffer += sprintf (buffer,"XID:\t%d\n", vx_task_xid(p));
992 vxi = task_get_vx_info(p);
996 buffer += sprintf (buffer,"BCaps:\t%016llx\n"
997 ,(unsigned long long)vxi->vx_bcaps);
998 buffer += sprintf (buffer,"CCaps:\t%016llx\n"
999 ,(unsigned long long)vxi->vx_ccaps);
1000 buffer += sprintf (buffer,"CFlags:\t%016llx\n"
1001 ,(unsigned long long)vxi->vx_flags);
1002 buffer += sprintf (buffer,"CIPid:\t%d\n"
1007 return buffer - orig;
1011 int proc_pid_nx_info(struct task_struct *p, char *buffer)
1013 struct nx_info *nxi;
1014 char * orig = buffer;
1017 buffer += sprintf (buffer,"NID:\t%d\n", nx_task_nid(p));
1019 nxi = task_get_nx_info(p);
1023 buffer += sprintf (buffer,"NCaps:\t%016llx\n"
1024 ,(unsigned long long)nxi->nx_ncaps);
1025 buffer += sprintf (buffer,"NFlags:\t%016llx\n"
1026 ,(unsigned long long)nxi->nx_flags);
1028 for (i=0; i<nxi->nbipv4; i++){
1029 buffer += sprintf (buffer,
1030 "V4Root[%d]:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i
1031 ,NIPQUAD(nxi->ipv4[i])
1032 ,NIPQUAD(nxi->mask[i]));
1034 buffer += sprintf (buffer,
1035 "V4Root[bcast]:\t%d.%d.%d.%d\n"
1036 ,NIPQUAD(nxi->v4_bcast));
1040 return buffer - orig;