*
* Virtual Context Support
*
- * Copyright (C) 2003-2004 Herbert Pötzl
+ * Copyright (C) 2003-2007 Herbert Pötzl
*
* V0.01 basic structure
* V0.02 adaptation vs1.3.0
* V0.05 next generation procfs
* V0.06 inode validation
* V0.07 generic rewrite vid
+ * V0.08 remove inode type
*
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/proc_fs.h>
-#include <linux/vserver.h>
-#include <linux/vs_base.h>
+#include <linux/sched.h>
#include <linux/vs_context.h>
#include <linux/vs_network.h>
+#include <linux/vs_cvirt.h>
+
+#include <linux/vserver/switch.h>
+#include <linux/vserver/global.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
+#include "cvirt_proc.h"
+#include "cacct_proc.h"
+#include "limit_proc.h"
+#include "sched_proc.h"
+#include "vci_config.h"
static struct proc_dir_entry *proc_virtual;
-static struct proc_dir_entry *proc_vnet;
-
-
-enum vid_directory_inos {
- PROC_XID_INO = 32,
- PROC_XID_INFO,
- PROC_XID_STATUS,
- PROC_XID_LIMIT,
- PROC_XID_SCHED,
- PROC_XID_CVIRT,
- PROC_XID_CACCT,
-
- PROC_NID_INO = 64,
- PROC_NID_INFO,
- PROC_NID_STATUS,
-};
-
-#define PROC_VID_MASK 0x60
+static struct proc_dir_entry *proc_virtnet;
/* first the actual feeds */
-static int proc_virtual_info(int vid, char *buffer)
+static int proc_vci(char *buffer)
{
return sprintf(buffer,
"VCIVersion:\t%04x:%04x\n"
"VCISyscall:\t%d\n"
+ "VCIKernel:\t%08x\n"
,VCI_VERSION >> 16
,VCI_VERSION & 0xFFFF
,__NR_vserver
+ ,vci_kernel_config()
);
}
+static int proc_virtual_info(char *buffer)
+{
+ return proc_vci(buffer);
+}
-int proc_xid_info (int vid, char *buffer)
+static int proc_virtual_status(char *buffer)
+{
+ return sprintf(buffer,
+ "#CTotal:\t%d\n"
+ "#CActive:\t%d\n"
+ "#NSProxy:\t%d\t%d %d %d %d\n"
+ ,atomic_read(&vx_global_ctotal)
+ ,atomic_read(&vx_global_cactive)
+ ,atomic_read(&vs_global_nsproxy)
+ ,atomic_read(&vs_global_fs)
+ ,atomic_read(&vs_global_mnt_ns)
+ ,atomic_read(&vs_global_uts_ns)
+ ,atomic_read(&vs_global_ipc_ns)
+ );
+}
+
+
+int proc_vxi_info (struct vx_info *vxi, char *buffer)
{
- struct vx_info *vxi;
int length;
- vxi = locate_vx_info(vid);
- if (!vxi)
- return 0;
length = sprintf(buffer,
"ID:\t%d\n"
"Info:\t%p\n"
,vxi
,vxi->vx_initpid
);
- put_vx_info(vxi);
return length;
}
-int proc_xid_status (int vid, char *buffer)
+int proc_vxi_status (struct vx_info *vxi, char *buffer)
{
- struct vx_info *vxi;
int length;
- vxi = locate_vx_info(vid);
- if (!vxi)
- return 0;
length = sprintf(buffer,
- "UseCnt:\t%d\n"
- "RefCnt:\t%d\n"
+ "UseCnt:\t%d\n"
+ "Tasks:\t%d\n"
"Flags:\t%016llx\n"
"BCaps:\t%016llx\n"
"CCaps:\t%016llx\n"
- "Ticks:\t%d\n"
+ "Spaces:\t%08lx\n"
,atomic_read(&vxi->vx_usecnt)
- ,atomic_read(&vxi->vx_refcnt)
+ ,atomic_read(&vxi->vx_tasks)
,(unsigned long long)vxi->vx_flags
,(unsigned long long)vxi->vx_bcaps
,(unsigned long long)vxi->vx_ccaps
- ,atomic_read(&vxi->limit.ticks)
+ ,vxi->vx_nsmask
);
- put_vx_info(vxi);
return length;
}
-int proc_xid_limit (int vid, char *buffer)
+int proc_vxi_limit (struct vx_info *vxi, char *buffer)
{
- struct vx_info *vxi;
- int length;
-
- vxi = locate_vx_info(vid);
- if (!vxi)
- return 0;
- length = vx_info_proc_limit(&vxi->limit, buffer);
- put_vx_info(vxi);
- return length;
+ return vx_info_proc_limit(&vxi->limit, buffer);
}
-int proc_xid_sched (int vid, char *buffer)
+int proc_vxi_sched (struct vx_info *vxi, char *buffer)
{
- struct vx_info *vxi;
- int length;
+ int cpu, length;
- vxi = locate_vx_info(vid);
- if (!vxi)
- return 0;
length = vx_info_proc_sched(&vxi->sched, buffer);
- put_vx_info(vxi);
+ for_each_online_cpu(cpu) {
+ length += vx_info_proc_sched_pc(
+ &vx_per_cpu(vxi, sched_pc, cpu),
+ buffer + length, cpu);
+ }
return length;
}
-int proc_xid_cvirt (int vid, char *buffer)
+int proc_vxi_nsproxy (struct vx_info *vxi, char *buffer)
{
- struct vx_info *vxi;
- int length;
+ return vx_info_proc_nsproxy(vxi->vx_nsproxy, buffer);
+}
- vxi = locate_vx_info(vid);
- if (!vxi)
- return 0;
+int proc_vxi_cvirt (struct vx_info *vxi, char *buffer)
+{
+ int cpu, length;
+
+ vx_update_load(vxi);
length = vx_info_proc_cvirt(&vxi->cvirt, buffer);
- put_vx_info(vxi);
+ for_each_online_cpu(cpu) {
+ length += vx_info_proc_cvirt_pc(
+ &vx_per_cpu(vxi, cvirt_pc, cpu),
+ buffer + length, cpu);
+ }
return length;
}
-int proc_xid_cacct (int vid, char *buffer)
+int proc_vxi_cacct (struct vx_info *vxi, char *buffer)
{
- struct vx_info *vxi;
- int length;
-
- vxi = locate_vx_info(vid);
- if (!vxi)
- return 0;
- length = vx_info_proc_cacct(&vxi->cacct, buffer);
- put_vx_info(vxi);
- return length;
+ return vx_info_proc_cacct(&vxi->cacct, buffer);
}
-static int proc_vnet_info(int vid, char *buffer)
+static int proc_virtnet_info(char *buffer)
+{
+ return proc_vci(buffer);
+}
+
+static int proc_virtnet_status(char *buffer)
{
return sprintf(buffer,
- "VCIVersion:\t%04x:%04x\n"
- "VCISyscall:\t%d\n"
- ,VCI_VERSION >> 16
- ,VCI_VERSION & 0xFFFF
- ,__NR_vserver
+ "#CTotal:\t%d\n"
+ "#CActive:\t%d\n"
+ ,atomic_read(&nx_global_ctotal)
+ ,atomic_read(&nx_global_cactive)
);
}
-#define atoquad(a) \
- (((a)>>0) & 0xff), (((a)>>8) & 0xff), \
- (((a)>>16) & 0xff), (((a)>>24) & 0xff)
-
-int proc_nid_info (int vid, char *buffer)
+int proc_nxi_info (struct nx_info *nxi, char *buffer)
{
- struct nx_info *nxi;
int length, i;
- nxi = locate_nx_info(vid);
- if (!nxi)
- return 0;
length = sprintf(buffer,
"ID:\t%d\n"
"Info:\t%p\n"
);
for (i=0; i<nxi->nbipv4; i++) {
length += sprintf(buffer + length,
- "%d:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i,
- atoquad(nxi->ipv4[i]),
- atoquad(nxi->mask[i]));
+ "%d:\t" NIPQUAD_FMT "/" NIPQUAD_FMT "\n", i,
+ NIPQUAD(nxi->ipv4[i]), NIPQUAD(nxi->mask[i]));
}
- put_nx_info(nxi);
return length;
}
-int proc_nid_status (int vid, char *buffer)
+int proc_nxi_status (struct nx_info *nxi, char *buffer)
{
- struct nx_info *nxi;
int length;
- nxi = locate_nx_info(vid);
- if (!nxi)
- return 0;
length = sprintf(buffer,
- "UseCnt:\t%d\n"
- "RefCnt:\t%d\n"
+ "UseCnt:\t%d\n"
+ "Tasks:\t%d\n"
+ "Flags:\t%016llx\n"
+ "NCaps:\t%016llx\n"
,atomic_read(&nxi->nx_usecnt)
- ,atomic_read(&nxi->nx_refcnt)
+ ,atomic_read(&nxi->nx_tasks)
+ ,(unsigned long long)nxi->nx_flags
+ ,(unsigned long long)nxi->nx_ncaps
);
- put_nx_info(nxi);
return length;
}
-/* here the inode helpers */
-
-#define fake_ino(id,ino) (((id)<<16)|(ino))
-
-#define inode_vid(i) ((i)->i_ino >> 16)
-#define inode_type(i) ((i)->i_ino & 0xFFFF)
-
-#define MAX_MULBY10 ((~0U-9)/10)
+/* here the inode helpers */
+struct vs_entry {
+ int len;
+ char *name;
+ mode_t mode;
+ struct inode_operations *iop;
+ struct file_operations *fop;
+ union proc_op op;
+};
-static struct inode *proc_vid_make_inode(struct super_block * sb,
- int vid, int ino)
+static struct inode *vs_proc_make_inode(struct super_block *sb, struct vs_entry *p)
{
struct inode *inode = new_inode(sb);
if (!inode)
goto out;
- inode->i_mtime = inode->i_atime =
- inode->i_ctime = CURRENT_TIME;
- inode->i_ino = fake_ino(vid, ino);
+ inode->i_mode = p->mode;
+ if (p->iop)
+ inode->i_op = p->iop;
+ if (p->fop)
+ inode->i_fop = p->fop;
+
+ inode->i_nlink = (p->mode & S_IFDIR) ? 2 : 1;
+ inode->i_flags |= S_IMMUTABLE;
+
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_uid = 0;
inode->i_gid = 0;
- // inode->i_xid = xid;
+ inode->i_tag = 0;
out:
return inode;
}
-static int proc_vid_revalidate(struct dentry * dentry, struct nameidata *nd)
+static struct dentry *vs_proc_instantiate(struct inode *dir,
+ struct dentry *dentry, int id, void *ptr)
{
- struct inode * inode = dentry->d_inode;
- int vid, hashed=0;
+ struct vs_entry *p = ptr;
+ struct inode *inode = vs_proc_make_inode(dir->i_sb, p);
+ struct dentry *error = ERR_PTR(-EINVAL);
- vid = inode_vid(inode);
- switch (inode_type(inode) & PROC_VID_MASK) {
- case PROC_XID_INO:
- hashed = vx_info_is_hashed(vid);
- break;
- case PROC_NID_INO:
- hashed = nx_info_is_hashed(vid);
- break;
- }
- if (hashed)
+ if (!inode)
+ goto out;
+
+ PROC_I(inode)->op = p->op;
+ PROC_I(inode)->fd = id;
+ d_add(dentry, inode);
+ error = NULL;
+out:
+ return error;
+}
+
+/* Lookups */
+
+typedef struct dentry *instantiate_t(struct inode *, struct dentry *, int, void *);
+
+/*
+ * Fill a directory entry.
+ *
+ * If possible create the dcache entry and derive our inode number and
+ * file type from dcache entry.
+ *
+ * Since all of the proc inode numbers are dynamically generated, the inode
+ * numbers do not exist until the inode is cache. This means creating the
+ * the dcache entry in readdir is necessary to keep the inode numbers
+ * reported by readdir in sync with the inode numbers reported
+ * by stat.
+ */
+static int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+ char *name, int len, instantiate_t instantiate, int id, void *ptr)
+{
+ struct dentry *child, *dir = filp->f_dentry;
+ struct inode *inode;
+ struct qstr qname;
+ ino_t ino = 0;
+ unsigned type = DT_UNKNOWN;
+
+ qname.name = name;
+ qname.len = len;
+ qname.hash = full_name_hash(name, len);
+
+ child = d_lookup(dir, &qname);
+ if (!child) {
+ struct dentry *new;
+ new = d_alloc(dir, &qname);
+ if (new) {
+ child = instantiate(dir->d_inode, new, id, ptr);
+ if (child)
+ dput(new);
+ else
+ child = new;
+ }
+ }
+ if (!child || IS_ERR(child) || !child->d_inode)
+ goto end_instantiate;
+ inode = child->d_inode;
+ if (inode) {
+ ino = inode->i_ino;
+ type = inode->i_mode >> 12;
+ }
+ dput(child);
+end_instantiate:
+ if (!ino)
+ ino = find_inode_number(dir, &qname);
+ if (!ino)
+ ino = 1;
+ return filldir(dirent, name, len, filp->f_pos, ino, type);
+}
+
+
+
+/* get and revalidate vx_info/xid */
+
+static inline
+struct vx_info *get_proc_vx_info(struct inode *inode)
+{
+ return lookup_vx_info(PROC_I(inode)->fd);
+}
+
+static int proc_xid_revalidate(struct dentry * dentry, struct nameidata *nd)
+{
+ struct inode *inode = dentry->d_inode;
+ xid_t xid = PROC_I(inode)->fd;
+
+ if (!xid || xid_is_hashed(xid))
return 1;
d_drop(dentry);
return 0;
}
-/*
-static int proc_vid_delete_dentry(struct dentry * dentry)
+
+/* get and revalidate nx_info/nid */
+
+static int proc_nid_revalidate(struct dentry * dentry, struct nameidata *nd)
{
- return 1;
+ struct inode *inode = dentry->d_inode;
+ nid_t nid = PROC_I(inode)->fd;
+
+ if (!nid || nid_is_hashed(nid))
+ return 1;
+ d_drop(dentry);
+ return 0;
}
-*/
+
#define PROC_BLOCK_SIZE (PAGE_SIZE - 1024)
-static ssize_t proc_vid_info_read(struct file * file, char * buf,
+static ssize_t proc_vs_info_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_dentry->d_inode;
unsigned long page;
- ssize_t length;
- ssize_t end;
- int vid;
+ ssize_t length = 0;
if (count > PROC_BLOCK_SIZE)
count = PROC_BLOCK_SIZE;
+
+ /* fade that out as soon as stable */
+ WARN_ON(PROC_I(inode)->fd);
+
if (!(page = __get_free_page(GFP_KERNEL)))
return -ENOMEM;
- vid = inode_vid(inode);
- length = PROC_I(inode)->op.proc_vid_read(vid, (char*)page);
+ BUG_ON(!PROC_I(inode)->op.proc_vs_read);
+ length = PROC_I(inode)->op.proc_vs_read((char*)page);
+
+ if (length >= 0)
+ length = simple_read_from_buffer(buf, count, ppos,
+ (char *)page, length);
- if (length < 0) {
- free_page(page);
- return length;
- }
- /* Static 4kB (or whatever) block capacity */
- if (*ppos >= length) {
- free_page(page);
- return 0;
- }
- if (count + *ppos > length)
- count = length - *ppos;
- end = count + *ppos;
- copy_to_user(buf, (char *) page + *ppos, count);
- *ppos = end;
free_page(page);
- return count;
+ return length;
}
+static ssize_t proc_vx_info_read(struct file * file, char __user * buf,
+ size_t count, loff_t *ppos)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct vx_info *vxi = NULL;
+ xid_t xid = PROC_I(inode)->fd;
+ unsigned long page;
+ ssize_t length = 0;
+ if (count > PROC_BLOCK_SIZE)
+ count = PROC_BLOCK_SIZE;
+ /* fade that out as soon as stable */
+ WARN_ON(!xid);
+ vxi = lookup_vx_info(xid);
+ if (!vxi)
+ goto out;
+ length = -ENOMEM;
+ if (!(page = __get_free_page(GFP_KERNEL)))
+ goto out_put;
-/* here comes the lower level (vid) */
+ BUG_ON(!PROC_I(inode)->op.proc_vxi_read);
+ length = PROC_I(inode)->op.proc_vxi_read(vxi, (char*)page);
-static struct file_operations proc_vid_info_file_operations = {
- read: proc_vid_info_read,
-};
+ if (length >= 0)
+ length = simple_read_from_buffer(buf, count, ppos,
+ (char *)page, length);
-static struct dentry_operations proc_vid_dentry_operations = {
- d_revalidate: proc_vid_revalidate,
-// d_delete: proc_vid_delete_dentry,
-};
+ free_page(page);
+out_put:
+ put_vx_info(vxi);
+out:
+ return length;
+}
+static ssize_t proc_nx_info_read(struct file * file, char __user * buf,
+ size_t count, loff_t *ppos)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct nx_info *nxi = NULL;
+ nid_t nid = PROC_I(inode)->fd;
+ unsigned long page;
+ ssize_t length = 0;
-struct vid_entry {
- int type;
- int len;
- char *name;
- mode_t mode;
+ if (count > PROC_BLOCK_SIZE)
+ count = PROC_BLOCK_SIZE;
+
+ /* fade that out as soon as stable */
+ WARN_ON(!nid);
+ nxi = lookup_nx_info(nid);
+ if (!nxi)
+ goto out;
+
+ length = -ENOMEM;
+ if (!(page = __get_free_page(GFP_KERNEL)))
+ goto out_put;
+
+ BUG_ON(!PROC_I(inode)->op.proc_nxi_read);
+ length = PROC_I(inode)->op.proc_nxi_read(nxi, (char*)page);
+
+ if (length >= 0)
+ length = simple_read_from_buffer(buf, count, ppos,
+ (char *)page, length);
+
+ free_page(page);
+out_put:
+ put_nx_info(nxi);
+out:
+ return length;
+}
+
+
+
+/* here comes the lower level */
+
+
+#define NOD(NAME, MODE, IOP, FOP, OP) { \
+ .len = sizeof(NAME) - 1, \
+ .name = (NAME), \
+ .mode = MODE, \
+ .iop = IOP, \
+ .fop = FOP, \
+ .op = OP, \
+}
+
+
+#define DIR(NAME, MODE, OTYPE) \
+ NOD(NAME, (S_IFDIR|(MODE)), \
+ &proc_##OTYPE##_inode_operations, \
+ &proc_##OTYPE##_file_operations, { } )
+
+#define INF(NAME, MODE, OTYPE) \
+ NOD(NAME, (S_IFREG|(MODE)), NULL, \
+ &proc_vs_info_file_operations, \
+ { .proc_vs_read = &proc_##OTYPE } )
+
+#define VINF(NAME, MODE, OTYPE) \
+ NOD(NAME, (S_IFREG|(MODE)), NULL, \
+ &proc_vx_info_file_operations, \
+ { .proc_vxi_read = &proc_##OTYPE } )
+
+#define NINF(NAME, MODE, OTYPE) \
+ NOD(NAME, (S_IFREG|(MODE)), NULL, \
+ &proc_nx_info_file_operations, \
+ { .proc_nxi_read = &proc_##OTYPE } )
+
+
+static struct file_operations proc_vs_info_file_operations = {
+ .read = proc_vs_info_read,
};
-#define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
+static struct file_operations proc_vx_info_file_operations = {
+ .read = proc_vx_info_read,
+};
-static struct vid_entry vx_base_stuff[] = {
- E(PROC_XID_INFO, "info", S_IFREG|S_IRUGO),
- E(PROC_XID_STATUS, "status", S_IFREG|S_IRUGO),
- E(PROC_XID_LIMIT, "limit", S_IFREG|S_IRUGO),
- E(PROC_XID_SCHED, "sched", S_IFREG|S_IRUGO),
- E(PROC_XID_CVIRT, "cvirt", S_IFREG|S_IRUGO),
- E(PROC_XID_CACCT, "cacct", S_IFREG|S_IRUGO),
- {0,0,NULL,0}
+static struct dentry_operations proc_xid_dentry_operations = {
+ .d_revalidate = proc_xid_revalidate,
};
-static struct vid_entry vn_base_stuff[] = {
- E(PROC_NID_INFO, "info", S_IFREG|S_IRUGO),
- E(PROC_NID_STATUS, "status", S_IFREG|S_IRUGO),
- {0,0,NULL,0}
+static struct vs_entry vx_base_stuff[] = {
+ VINF("info", S_IRUGO, vxi_info),
+ VINF("status", S_IRUGO, vxi_status),
+ VINF("limit", S_IRUGO, vxi_limit),
+ VINF("sched", S_IRUGO, vxi_sched),
+ VINF("nsproxy", S_IRUGO, vxi_nsproxy),
+ VINF("cvirt", S_IRUGO, vxi_cvirt),
+ VINF("cacct", S_IRUGO, vxi_cacct),
+ {}
};
-static struct dentry *proc_vid_lookup(struct inode *dir,
- struct dentry *dentry, struct nameidata *nd)
-{
- struct inode *inode;
- struct vid_entry *p;
- int error;
- error = -ENOENT;
- inode = NULL;
+static struct dentry *proc_xid_instantiate(struct inode *dir,
+ struct dentry *dentry, int id, void *ptr)
+{
+ dentry->d_op = &proc_xid_dentry_operations;
+ return vs_proc_instantiate(dir, dentry, id, ptr);
+}
- switch (inode_type(dir)) {
- case PROC_XID_INO:
- p = vx_base_stuff;
- break;
- case PROC_NID_INO:
- p = vn_base_stuff;
- break;
- default:
- goto out;
- }
+static struct dentry *proc_xid_lookup(struct inode *dir,
+ struct dentry *dentry, struct nameidata *nd)
+{
+ struct vs_entry *p = vx_base_stuff;
+ struct dentry *error = ERR_PTR(-ENOENT);
for (; p->name; p++) {
if (p->len != dentry->d_name.len)
if (!p->name)
goto out;
- error = -EINVAL;
- inode = proc_vid_make_inode(dir->i_sb, inode_vid(dir), p->type);
- if (!inode)
- goto out;
-
- switch(p->type) {
- case PROC_XID_INFO:
- PROC_I(inode)->op.proc_vid_read = proc_xid_info;
- break;
- case PROC_XID_STATUS:
- PROC_I(inode)->op.proc_vid_read = proc_xid_status;
- break;
- case PROC_XID_LIMIT:
- PROC_I(inode)->op.proc_vid_read = proc_xid_limit;
- break;
- case PROC_XID_SCHED:
- PROC_I(inode)->op.proc_vid_read = proc_xid_sched;
- break;
- case PROC_XID_CVIRT:
- PROC_I(inode)->op.proc_vid_read = proc_xid_cvirt;
- break;
- case PROC_XID_CACCT:
- PROC_I(inode)->op.proc_vid_read = proc_xid_cacct;
- break;
-
- case PROC_NID_INFO:
- PROC_I(inode)->op.proc_vid_read = proc_nid_info;
- break;
- case PROC_NID_STATUS:
- PROC_I(inode)->op.proc_vid_read = proc_nid_status;
- break;
-
- default:
- printk("procfs: impossible type (%d)",p->type);
- iput(inode);
- return ERR_PTR(-EINVAL);
- }
- inode->i_mode = p->mode;
-// inode->i_op = &proc_vid_info_inode_operations;
- inode->i_fop = &proc_vid_info_file_operations;
- inode->i_nlink = 1;
- inode->i_flags|=S_IMMUTABLE;
-
- dentry->d_op = &proc_vid_dentry_operations;
- d_add(dentry, inode);
- error = 0;
+ error = proc_xid_instantiate(dir, dentry, PROC_I(dir)->fd, p);
out:
- return ERR_PTR(error);
+ return error;
}
-
-static int proc_vid_readdir(struct file * filp,
+static int proc_xid_readdir(struct file * filp,
void * dirent, filldir_t filldir)
{
- int i, size;
- struct inode *inode = filp->f_dentry->d_inode;
- struct vid_entry *p;
-
- i = filp->f_pos;
- switch (i) {
- case 0:
- if (filldir(dirent, ".", 1, i,
- inode->i_ino, DT_DIR) < 0)
- return 0;
- i++;
- filp->f_pos++;
- /* fall through */
- case 1:
- if (filldir(dirent, "..", 2, i,
- PROC_ROOT_INO, DT_DIR) < 0)
- return 0;
- i++;
- filp->f_pos++;
- /* fall through */
- default:
- i -= 2;
- switch (inode_type(inode)) {
- case PROC_XID_INO:
- size = sizeof(vx_base_stuff);
- p = vx_base_stuff + i;
- break;
- case PROC_NID_INO:
- size = sizeof(vn_base_stuff);
- p = vn_base_stuff + i;
- break;
- default:
- return 1;
- }
- if (i >= size/sizeof(struct vid_entry))
- return 1;
- while (p->name) {
- if (filldir(dirent, p->name, p->len,
- filp->f_pos, fake_ino(inode_vid(inode),
- p->type), p->mode >> 12) < 0)
- return 0;
- filp->f_pos++;
- p++;
- }
+ struct dentry *dentry = filp->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct vs_entry *p = vx_base_stuff;
+ int size = sizeof(vx_base_stuff)/sizeof(struct vs_entry);
+ int pos, index;
+ u64 ino;
+
+ pos = filp->f_pos;
+ switch (pos) {
+ case 0:
+ ino = inode->i_ino;
+ if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0)
+ goto out;
+ pos++;
+ /* fall through */
+ case 1:
+ ino = parent_ino(dentry);
+ if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0)
+ goto out;
+ pos++;
+ /* fall through */
+ default:
+ index = pos - 2;
+ if (index >= size)
+ goto out;
+ for (p += index; p->name; p++) {
+ if (proc_fill_cache(filp, dirent, filldir, p->name, p->len,
+ vs_proc_instantiate, PROC_I(inode)->fd, p))
+ goto out;
+ pos++;
+ }
}
+out:
+ filp->f_pos = pos;
return 1;
}
+static struct file_operations proc_nx_info_file_operations = {
+ .read = proc_nx_info_read,
+};
-/* now the upper level (virtual) */
-
-static struct file_operations proc_vid_file_operations = {
- read: generic_read_dir,
- readdir: proc_vid_readdir,
+static struct dentry_operations proc_nid_dentry_operations = {
+ .d_revalidate = proc_nid_revalidate,
};
-static struct inode_operations proc_vid_inode_operations = {
- lookup: proc_vid_lookup,
+static struct vs_entry nx_base_stuff[] = {
+ NINF("info", S_IRUGO, nxi_info),
+ NINF("status", S_IRUGO, nxi_status),
+ {}
};
+static struct dentry *proc_nid_instantiate(struct inode *dir,
+ struct dentry *dentry, int id, void *ptr)
+{
+ dentry->d_op = &proc_nid_dentry_operations;
+ return vs_proc_instantiate(dir, dentry, id, ptr);
+}
-static __inline__ int atovid(const char *str, int len)
+static struct dentry *proc_nid_lookup(struct inode *dir,
+ struct dentry *dentry, struct nameidata *nd)
+{
+ struct vs_entry *p = nx_base_stuff;
+ struct dentry *error = ERR_PTR(-ENOENT);
+
+ for (; p->name; p++) {
+ if (p->len != dentry->d_name.len)
+ continue;
+ if (!memcmp(dentry->d_name.name, p->name, p->len))
+ break;
+ }
+ if (!p->name)
+ goto out;
+
+ error = proc_nid_instantiate(dir, dentry, PROC_I(dir)->fd, p);
+out:
+ return error;
+}
+
+static int proc_nid_readdir(struct file * filp,
+ void * dirent, filldir_t filldir)
+{
+ struct dentry *dentry = filp->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct vs_entry *p = nx_base_stuff;
+ int size = sizeof(nx_base_stuff)/sizeof(struct vs_entry);
+ int pos, index;
+ u64 ino;
+
+ pos = filp->f_pos;
+ switch (pos) {
+ case 0:
+ ino = inode->i_ino;
+ if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0)
+ goto out;
+ pos++;
+ /* fall through */
+ case 1:
+ ino = parent_ino(dentry);
+ if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0)
+ goto out;
+ pos++;
+ /* fall through */
+ default:
+ index = pos - 2;
+ if (index >= size)
+ goto out;
+ for (p += index; p->name; p++) {
+ if (proc_fill_cache(filp, dirent, filldir, p->name, p->len,
+ vs_proc_instantiate, PROC_I(inode)->fd, p))
+ goto out;
+ pos++;
+ }
+ }
+out:
+ filp->f_pos = pos;
+ return 1;
+}
+
+
+#define MAX_MULBY10 ((~0U-9)/10)
+
+static inline int atovid(const char *str, int len)
{
int vid, c;
return vid;
}
+/* now the upper level (virtual) */
-struct dentry *proc_virtual_lookup(struct inode *dir,
- struct dentry * dentry, struct nameidata *nd)
-{
- int xid, len, ret;
- struct vx_info *vxi;
- const char *name;
- struct inode *inode;
- name = dentry->d_name.name;
- len = dentry->d_name.len;
- ret = -ENOMEM;
+static struct file_operations proc_xid_file_operations = {
+ .read = generic_read_dir,
+ .readdir = proc_xid_readdir,
+};
- if (len == 7 && !memcmp(name, "current", 7)) {
- inode = new_inode(dir->i_sb);
- if (!inode)
- goto out;
- inode->i_mtime = inode->i_atime =
- inode->i_ctime = CURRENT_TIME;
- inode->i_ino = fake_ino(1, PROC_XID_INO);
- inode->i_mode = S_IFLNK|S_IRWXUGO;
- inode->i_uid = inode->i_gid = 0;
- inode->i_size = 64;
-// inode->i_op = &proc_current_inode_operations;
- d_add(dentry, inode);
- return NULL;
- }
- if (len == 4 && !memcmp(name, "info", 4)) {
- inode = proc_vid_make_inode(dir->i_sb, 0, PROC_XID_INFO);
- if (!inode)
- goto out;
- inode->i_fop = &proc_vid_info_file_operations;
- PROC_I(inode)->op.proc_vid_read = proc_virtual_info;
- inode->i_mode = S_IFREG|S_IRUGO;
-// inode->i_size = 64;
-// inode->i_op = &proc_current_inode_operations;
- d_add(dentry, inode);
- return NULL;
- }
+static struct inode_operations proc_xid_inode_operations = {
+ .lookup = proc_xid_lookup,
+};
- ret = -ENOENT;
- xid = atovid(name, len);
- if (xid < 0)
- goto out;
- vxi = locate_vx_info(xid);
- if (!vxi)
- goto out;
+static struct vs_entry vx_virtual_stuff[] = {
+ INF("info", S_IRUGO, virtual_info),
+ INF("status", S_IRUGO, virtual_status),
+ DIR(NULL, S_IRUGO|S_IXUGO, xid),
+};
- inode = NULL;
- if (vx_check(xid, VX_ADMIN|VX_WATCH|VX_IDENT))
- inode = proc_vid_make_inode(dir->i_sb,
- vxi->vx_id, PROC_XID_INO);
- if (!inode)
- goto out_release;
- inode->i_mode = S_IFDIR|S_IRUGO;
- inode->i_op = &proc_vid_inode_operations;
- inode->i_fop = &proc_vid_file_operations;
- inode->i_nlink = 2;
- inode->i_flags|=S_IMMUTABLE;
+static struct dentry *proc_virtual_lookup(struct inode *dir,
+ struct dentry *dentry, struct nameidata *nd)
+{
+ struct vs_entry *p = vx_virtual_stuff;
+ struct dentry *error = ERR_PTR(-ENOENT);
+ int id = 0;
- dentry->d_op = &proc_vid_dentry_operations;
- d_add(dentry, inode);
- ret = 0;
-
-out_release:
- put_vx_info(vxi);
+ for (; p->name; p++) {
+ if (p->len != dentry->d_name.len)
+ continue;
+ if (!memcmp(dentry->d_name.name, p->name, p->len))
+ break;
+ }
+ if (p->name)
+ goto instantiate;
+
+ id = atovid(dentry->d_name.name, dentry->d_name.len);
+ if ((id < 0) || !xid_is_hashed(id))
+ goto out;
+
+instantiate:
+ error = proc_xid_instantiate(dir, dentry, id, p);
out:
- return ERR_PTR(ret);
+ return error;
}
+static struct file_operations proc_nid_file_operations = {
+ .read = generic_read_dir,
+ .readdir = proc_nid_readdir,
+};
-struct dentry *proc_vnet_lookup(struct inode *dir,
- struct dentry * dentry, struct nameidata *nd)
+static struct inode_operations proc_nid_inode_operations = {
+ .lookup = proc_nid_lookup,
+};
+
+static struct vs_entry nx_virtnet_stuff[] = {
+ INF("info", S_IRUGO, virtnet_info),
+ INF("status", S_IRUGO, virtnet_status),
+ DIR(NULL, S_IRUGO|S_IXUGO, nid),
+};
+
+
+static struct dentry *proc_virtnet_lookup(struct inode *dir,
+ struct dentry *dentry, struct nameidata *nd)
{
- int nid, len, ret;
- struct nx_info *nxi;
- const char *name;
- struct inode *inode;
+ struct vs_entry *p = nx_virtnet_stuff;
+ struct dentry *error = ERR_PTR(-ENOENT);
+ int id = 0;
- name = dentry->d_name.name;
- len = dentry->d_name.len;
- ret = -ENOMEM;
- if (len == 7 && !memcmp(name, "current", 7)) {
- inode = new_inode(dir->i_sb);
- if (!inode)
- goto out;
- inode->i_mtime = inode->i_atime =
- inode->i_ctime = CURRENT_TIME;
- inode->i_ino = fake_ino(1, PROC_NID_INO);
- inode->i_mode = S_IFLNK|S_IRWXUGO;
- inode->i_uid = inode->i_gid = 0;
- inode->i_size = 64;
-// inode->i_op = &proc_current_inode_operations;
- d_add(dentry, inode);
- return NULL;
- }
- if (len == 4 && !memcmp(name, "info", 4)) {
- inode = proc_vid_make_inode(dir->i_sb, 0, PROC_NID_INFO);
- if (!inode)
- goto out;
- inode->i_fop = &proc_vid_info_file_operations;
- PROC_I(inode)->op.proc_vid_read = proc_vnet_info;
- inode->i_mode = S_IFREG|S_IRUGO;
-// inode->i_size = 64;
-// inode->i_op = &proc_current_inode_operations;
- d_add(dentry, inode);
- return NULL;
+ for (; p->name; p++) {
+ if (p->len != dentry->d_name.len)
+ continue;
+ if (!memcmp(dentry->d_name.name, p->name, p->len))
+ break;
}
+ if (p->name)
+ goto instantiate;
- ret = -ENOENT;
- nid = atovid(name, len);
- if (nid < 0)
+ id = atovid(dentry->d_name.name, dentry->d_name.len);
+ if ((id < 0) || !nid_is_hashed(id))
goto out;
- nxi = locate_nx_info(nid);
- if (!nxi)
- goto out;
-
- inode = NULL;
- if (1)
- inode = proc_vid_make_inode(dir->i_sb,
- nxi->nx_id, PROC_NID_INO);
- if (!inode)
- goto out_release;
-
- inode->i_mode = S_IFDIR|S_IRUGO;
- inode->i_op = &proc_vid_inode_operations;
- inode->i_fop = &proc_vid_file_operations;
- inode->i_nlink = 2;
- inode->i_flags|=S_IMMUTABLE;
- dentry->d_op = &proc_vid_dentry_operations;
- d_add(dentry, inode);
- ret = 0;
-
-out_release:
- put_nx_info(nxi);
+instantiate:
+ error = proc_nid_instantiate(dir, dentry, id, p);
out:
- return ERR_PTR(ret);
+ return error;
}
-
#define PROC_NUMBUF 10
#define PROC_MAXVIDS 32
int proc_virtual_readdir(struct file * filp,
void * dirent, filldir_t filldir)
{
+ struct dentry *dentry = filp->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct vs_entry *p = vx_virtual_stuff;
+ int size = sizeof(vx_virtual_stuff)/sizeof(struct vs_entry);
+ int pos, index;
unsigned int xid_array[PROC_MAXVIDS];
char buf[PROC_NUMBUF];
- unsigned int nr = filp->f_pos-3;
unsigned int nr_xids, i;
- ino_t ino;
-
- switch ((long)filp->f_pos) {
- case 0:
- ino = fake_ino(0, PROC_XID_INO);
- if (filldir(dirent, ".", 1,
- filp->f_pos, ino, DT_DIR) < 0)
- return 0;
- filp->f_pos++;
- /* fall through */
- case 1:
- ino = filp->f_dentry->d_parent->d_inode->i_ino;
- if (filldir(dirent, "..", 2,
- filp->f_pos, ino, DT_DIR) < 0)
- return 0;
- filp->f_pos++;
- /* fall through */
- case 2:
- ino = fake_ino(0, PROC_XID_INFO);
- if (filldir(dirent, "info", 4,
- filp->f_pos, ino, DT_LNK) < 0)
- return 0;
- filp->f_pos++;
- /* fall through */
- case 3:
- if (current->xid > 1) {
- ino = fake_ino(1, PROC_XID_INO);
- if (filldir(dirent, "current", 7,
- filp->f_pos, ino, DT_LNK) < 0)
- return 0;
- }
- filp->f_pos++;
- }
-
- nr_xids = get_xid_list(nr, xid_array, PROC_MAXVIDS);
- for (i = 0; i < nr_xids; i++) {
- int xid = xid_array[i];
- ino_t ino = fake_ino(xid, PROC_XID_INO);
- unsigned int j = PROC_NUMBUF;
+ u64 ino;
- do buf[--j] = '0' + (xid % 10); while (xid/=10);
-
- if (filldir(dirent, buf+j, PROC_NUMBUF-j,
- filp->f_pos, ino, DT_DIR) < 0)
- break;
- filp->f_pos++;
+ pos = filp->f_pos;
+ switch (pos) {
+ case 0:
+ ino = inode->i_ino;
+ if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0)
+ goto out;
+ pos++;
+ /* fall through */
+ case 1:
+ ino = parent_ino(dentry);
+ if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0)
+ goto out;
+ pos++;
+ /* fall through */
+ default:
+ index = pos - 2;
+ if (index >= size)
+ goto entries;
+ for (p += index; p->name; p++) {
+ if (proc_fill_cache(filp, dirent, filldir, p->name, p->len,
+ vs_proc_instantiate, 0, p))
+ goto out;
+ pos++;
+ }
+ entries:
+ index = pos - size;
+ p = &vx_virtual_stuff[size-1];
+ nr_xids = get_xid_list(index, xid_array, PROC_MAXVIDS);
+ for (i = 0; i < nr_xids; i++) {
+ int n, xid = xid_array[i];
+ unsigned int j = PROC_NUMBUF;
+
+ n = xid;
+ do buf[--j] = '0' + (n % 10); while (n /= 10);
+
+ if (proc_fill_cache(filp, dirent, filldir, buf+j, PROC_NUMBUF-j,
+ vs_proc_instantiate, xid, p))
+ goto out;
+ pos++;
+ }
}
+out:
+ filp->f_pos = pos;
return 0;
}
+static int proc_virtual_getattr(struct vfsmount *mnt,
+ struct dentry *dentry, struct kstat *stat)
+{
+ struct inode *inode = dentry->d_inode;
+
+ generic_fillattr(inode, stat);
+ stat->nlink = 2 + atomic_read(&vx_global_cactive);
+ return 0;
+}
static struct file_operations proc_virtual_dir_operations = {
- read: generic_read_dir,
- readdir: proc_virtual_readdir,
+ .read = generic_read_dir,
+ .readdir = proc_virtual_readdir,
};
static struct inode_operations proc_virtual_dir_inode_operations = {
- lookup: proc_virtual_lookup,
+ .getattr = proc_virtual_getattr,
+ .lookup = proc_virtual_lookup,
};
-int proc_vnet_readdir(struct file * filp,
+
+
+
+int proc_virtnet_readdir(struct file * filp,
void * dirent, filldir_t filldir)
{
+ struct dentry *dentry = filp->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct vs_entry *p = nx_virtnet_stuff;
+ int size = sizeof(nx_virtnet_stuff)/sizeof(struct vs_entry);
+ int pos, index;
unsigned int nid_array[PROC_MAXVIDS];
char buf[PROC_NUMBUF];
- unsigned int nr = filp->f_pos-3;
unsigned int nr_nids, i;
- ino_t ino;
-
- switch ((long)filp->f_pos) {
- case 0:
- ino = fake_ino(0, PROC_NID_INO);
- if (filldir(dirent, ".", 1,
- filp->f_pos, ino, DT_DIR) < 0)
- return 0;
- filp->f_pos++;
- /* fall through */
- case 1:
- ino = filp->f_dentry->d_parent->d_inode->i_ino;
- if (filldir(dirent, "..", 2,
- filp->f_pos, ino, DT_DIR) < 0)
- return 0;
- filp->f_pos++;
- /* fall through */
- case 2:
- ino = fake_ino(0, PROC_NID_INFO);
- if (filldir(dirent, "info", 4,
- filp->f_pos, ino, DT_LNK) < 0)
- return 0;
- filp->f_pos++;
- /* fall through */
- case 3:
- if (current->xid > 1) {
- ino = fake_ino(1, PROC_NID_INO);
- if (filldir(dirent, "current", 7,
- filp->f_pos, ino, DT_LNK) < 0)
- return 0;
- }
- filp->f_pos++;
- }
-
- nr_nids = get_nid_list(nr, nid_array, PROC_MAXVIDS);
- for (i = 0; i < nr_nids; i++) {
- int nid = nid_array[i];
- ino_t ino = fake_ino(nid, PROC_NID_INO);
- unsigned long j = PROC_NUMBUF;
+ u64 ino;
- do buf[--j] = '0' + (nid % 10); while (nid/=10);
-
- if (filldir(dirent, buf+j, PROC_NUMBUF-j,
- filp->f_pos, ino, DT_DIR) < 0)
- break;
- filp->f_pos++;
+ pos = filp->f_pos;
+ switch (pos) {
+ case 0:
+ ino = inode->i_ino;
+ if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0)
+ goto out;
+ pos++;
+ /* fall through */
+ case 1:
+ ino = parent_ino(dentry);
+ if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0)
+ goto out;
+ pos++;
+ /* fall through */
+ default:
+ index = pos - 2;
+ if (index >= size)
+ goto entries;
+ for (p += index; p->name; p++) {
+ if (proc_fill_cache(filp, dirent, filldir, p->name, p->len,
+ vs_proc_instantiate, 0, p))
+ goto out;
+ pos++;
+ }
+ entries:
+ index = pos - size;
+ p = &nx_virtnet_stuff[size-1];
+ nr_nids = get_nid_list(index, nid_array, PROC_MAXVIDS);
+ for (i = 0; i < nr_nids; i++) {
+ int n, nid = nid_array[i];
+ unsigned int j = PROC_NUMBUF;
+
+ n = nid;
+ do buf[--j] = '0' + (n % 10); while (n /= 10);
+
+ if (proc_fill_cache(filp, dirent, filldir, buf+j, PROC_NUMBUF-j,
+ vs_proc_instantiate, nid, p))
+ goto out;
+ pos++;
+ }
}
+out:
+ filp->f_pos = pos;
return 0;
}
+static int proc_virtnet_getattr(struct vfsmount *mnt,
+ struct dentry *dentry, struct kstat *stat)
+{
+ struct inode *inode = dentry->d_inode;
+
+ generic_fillattr(inode, stat);
+ stat->nlink = 2 + atomic_read(&nx_global_cactive);
+ return 0;
+}
-static struct file_operations proc_vnet_dir_operations = {
- read: generic_read_dir,
- readdir: proc_vnet_readdir,
+static struct file_operations proc_virtnet_dir_operations = {
+ .read = generic_read_dir,
+ .readdir = proc_virtnet_readdir,
};
-static struct inode_operations proc_vnet_dir_inode_operations = {
- lookup: proc_vnet_lookup,
+static struct inode_operations proc_virtnet_dir_inode_operations = {
+ .getattr = proc_virtnet_getattr,
+ .lookup = proc_virtnet_lookup,
};
}
proc_virtual = ent;
- ent = proc_mkdir("vnet", 0);
+ ent = proc_mkdir("virtnet", 0);
if (ent) {
- ent->proc_fops = &proc_vnet_dir_operations;
- ent->proc_iops = &proc_vnet_dir_inode_operations;
+ ent->proc_fops = &proc_virtnet_dir_operations;
+ ent->proc_iops = &proc_virtnet_dir_inode_operations;
}
- proc_vnet = ent;
+ proc_virtnet = ent;
}
/* per pid info */
-char *task_vx_info(struct task_struct *p, char *buffer)
-{
- return buffer + sprintf(buffer,
- "XID:\t%d\n"
- ,p->xid);
-}
-
int proc_pid_vx_info(struct task_struct *p, char *buffer)
{
+ struct vx_info *vxi;
char * orig = buffer;
- buffer = task_vx_info(p, buffer);
+ buffer += sprintf (buffer,"XID:\t%d\n", vx_task_xid(p));
+
+ vxi = task_get_vx_info(p);
+ if (!vxi)
+ goto out;
+
+ buffer += sprintf (buffer,"BCaps:\t%016llx\n"
+ ,(unsigned long long)vxi->vx_bcaps);
+ buffer += sprintf (buffer,"CCaps:\t%016llx\n"
+ ,(unsigned long long)vxi->vx_ccaps);
+ buffer += sprintf (buffer,"CFlags:\t%016llx\n"
+ ,(unsigned long long)vxi->vx_flags);
+ buffer += sprintf (buffer,"CIPid:\t%d\n"
+ ,vxi->vx_initpid);
+
+ put_vx_info(vxi);
+out:
return buffer - orig;
}
-char *task_nx_info(struct task_struct *p, char *buffer)
-{
- return buffer + sprintf(buffer,
- "NID:\t%d\n"
- ,p->nid);
-}
int proc_pid_nx_info(struct task_struct *p, char *buffer)
{
+ struct nx_info *nxi;
char * orig = buffer;
+ int i;
+
+ buffer += sprintf (buffer,"NID:\t%d\n", nx_task_nid(p));
+
+ nxi = task_get_nx_info(p);
+ if (!nxi)
+ goto out;
- buffer = task_nx_info(p, buffer);
+ buffer += sprintf (buffer,"NCaps:\t%016llx\n"
+ ,(unsigned long long)nxi->nx_ncaps);
+ buffer += sprintf (buffer,"NFlags:\t%016llx\n"
+ ,(unsigned long long)nxi->nx_flags);
+
+ for (i=0; i<nxi->nbipv4; i++){
+ buffer += sprintf (buffer,
+ "V4Root[%d]:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i
+ ,NIPQUAD(nxi->ipv4[i])
+ ,NIPQUAD(nxi->mask[i]));
+ }
+ buffer += sprintf (buffer,
+ "V4Root[bcast]:\t%d.%d.%d.%d\n"
+ ,NIPQUAD(nxi->v4_bcast));
+
+ put_nx_info(nxi);
+out:
return buffer - orig;
}