vserver 2.0-pre4
[linux-2.6.git] / kernel / vserver / proc.c
1 /*
2  *  linux/kernel/vserver/proc.c
3  *
4  *  Virtual Context Support
5  *
6  *  Copyright (C) 2003-2005  Herbert Pƶtzl
7  *
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  *
16  */
17
18 #include <linux/config.h>
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>
25
26 #include <linux/vserver/switch.h>
27
28 #include <asm/uaccess.h>
29 #include <asm/unistd.h>
30
31 #include "cvirt_proc.h"
32 #include "limit_proc.h"
33 #include "sched_proc.h"
34 #include "vci_config.h"
35
36 static struct proc_dir_entry *proc_virtual;
37
38 static struct proc_dir_entry *proc_vnet;
39
40
41 enum vid_directory_inos {
42         PROC_XID_INO = 32,
43         PROC_XID_INFO,
44         PROC_XID_STATUS,
45         PROC_XID_LIMIT,
46         PROC_XID_SCHED,
47         PROC_XID_CVIRT,
48         PROC_XID_CACCT,
49
50         PROC_NID_INO = 64,
51         PROC_NID_INFO,
52         PROC_NID_STATUS,
53 };
54
55 #define PROC_VID_MASK   0x60
56
57
58 /* first the actual feeds */
59
60
61 static int proc_virtual_info(int vid, char *buffer)
62 {
63         return sprintf(buffer,
64                 "VCIVersion:\t%04x:%04x\n"
65                 "VCISyscall:\t%d\n"
66                 "VCIKernel:\t%08x\n"
67                 ,VCI_VERSION >> 16
68                 ,VCI_VERSION & 0xFFFF
69                 ,__NR_vserver
70                 ,vci_kernel_config()
71                 );
72 }
73
74
75 int proc_xid_info (int vid, char *buffer)
76 {
77         struct vx_info *vxi;
78         int length;
79
80         vxi = locate_vx_info(vid);
81         if (!vxi)
82                 return 0;
83         length = sprintf(buffer,
84                 "ID:\t%d\n"
85                 "Info:\t%p\n"
86                 "Init:\t%d\n"
87                 ,vxi->vx_id
88                 ,vxi
89                 ,vxi->vx_initpid
90                 );
91         put_vx_info(vxi);
92         return length;
93 }
94
95 int proc_xid_status (int vid, char *buffer)
96 {
97         struct vx_info *vxi;
98         int length;
99
100         vxi = locate_vx_info(vid);
101         if (!vxi)
102                 return 0;
103         length = sprintf(buffer,
104                 "UseCnt:\t%d\n"
105                 "Tasks:\t%d\n"
106                 "Flags:\t%016llx\n"
107                 "BCaps:\t%016llx\n"
108                 "CCaps:\t%016llx\n"
109                 "Ticks:\t%d\n"
110                 ,atomic_read(&vxi->vx_usecnt)
111                 ,atomic_read(&vxi->vx_tasks)
112                 ,(unsigned long long)vxi->vx_flags
113                 ,(unsigned long long)vxi->vx_bcaps
114                 ,(unsigned long long)vxi->vx_ccaps
115                 ,atomic_read(&vxi->limit.ticks)
116                 );
117         put_vx_info(vxi);
118         return length;
119 }
120
121 int proc_xid_limit (int vid, char *buffer)
122 {
123         struct vx_info *vxi;
124         int length;
125
126         vxi = locate_vx_info(vid);
127         if (!vxi)
128                 return 0;
129         length = vx_info_proc_limit(&vxi->limit, buffer);
130         put_vx_info(vxi);
131         return length;
132 }
133
134 int proc_xid_sched (int vid, char *buffer)
135 {
136         struct vx_info *vxi;
137         int length;
138
139         vxi = locate_vx_info(vid);
140         if (!vxi)
141                 return 0;
142         length = vx_info_proc_sched(&vxi->sched, buffer);
143         put_vx_info(vxi);
144         return length;
145 }
146
147 int proc_xid_cvirt (int vid, char *buffer)
148 {
149         struct vx_info *vxi;
150         int length;
151
152         vxi = locate_vx_info(vid);
153         if (!vxi)
154                 return 0;
155         vx_update_load(vxi);
156         length = vx_info_proc_cvirt(&vxi->cvirt, buffer);
157         put_vx_info(vxi);
158         return length;
159 }
160
161 int proc_xid_cacct (int vid, char *buffer)
162 {
163         struct vx_info *vxi;
164         int length;
165
166         vxi = locate_vx_info(vid);
167         if (!vxi)
168                 return 0;
169         length = vx_info_proc_cacct(&vxi->cacct, buffer);
170         put_vx_info(vxi);
171         return length;
172 }
173
174
175 static int proc_vnet_info(int vid, char *buffer)
176 {
177         return sprintf(buffer,
178                 "VCIVersion:\t%04x:%04x\n"
179                 "VCISyscall:\t%d\n"
180                 ,VCI_VERSION >> 16
181                 ,VCI_VERSION & 0xFFFF
182                 ,__NR_vserver
183                 );
184 }
185
186 #define atoquad(a) \
187         (((a)>>0) & 0xff), (((a)>>8) & 0xff), \
188         (((a)>>16) & 0xff), (((a)>>24) & 0xff)
189
190 int proc_nid_info (int vid, char *buffer)
191 {
192         struct nx_info *nxi;
193         int length, i;
194
195         nxi = locate_nx_info(vid);
196         if (!nxi)
197                 return 0;
198         length = sprintf(buffer,
199                 "ID:\t%d\n"
200                 "Info:\t%p\n"
201                 ,nxi->nx_id
202                 ,nxi
203                 );
204         for (i=0; i<nxi->nbipv4; i++) {
205                 length += sprintf(buffer + length,
206                         "%d:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i,
207                         atoquad(nxi->ipv4[i]),
208                         atoquad(nxi->mask[i]));
209         }
210         put_nx_info(nxi);
211         return length;
212 }
213
214 int proc_nid_status (int vid, char *buffer)
215 {
216         struct nx_info *nxi;
217         int length;
218
219         nxi = locate_nx_info(vid);
220         if (!nxi)
221                 return 0;
222         length = sprintf(buffer,
223                 "UseCnt:\t%d\n"
224                 "RefCnt:\t%d\n"
225                 ,atomic_read(&nxi->nx_usecnt)
226                 ,atomic_read(&nxi->nx_refcnt)
227                 );
228         put_nx_info(nxi);
229         return length;
230 }
231
232 /* here the inode helpers */
233
234
235 #define fake_ino(id,nr) (((nr) & 0xFFFF) | \
236                         (((id) & 0xFFFF) << 16))
237
238 #define inode_vid(i)    (((i)->i_ino >> 16) & 0xFFFF)
239 #define inode_type(i)   ((i)->i_ino & 0xFFFF)
240
241 #define MAX_MULBY10     ((~0U-9)/10)
242
243
244 static struct inode *proc_vid_make_inode(struct super_block * sb,
245         int vid, int ino)
246 {
247         struct inode *inode = new_inode(sb);
248
249         if (!inode)
250                 goto out;
251
252         inode->i_mtime = inode->i_atime =
253                 inode->i_ctime = CURRENT_TIME;
254         inode->i_ino = fake_ino(vid, ino);
255
256         inode->i_uid = 0;
257         inode->i_gid = 0;
258         // inode->i_xid = xid;
259 out:
260         return inode;
261 }
262
263 static int proc_vid_revalidate(struct dentry * dentry, struct nameidata *nd)
264 {
265         struct inode * inode = dentry->d_inode;
266         int vid, hashed=0;
267
268         vid = inode_vid(inode);
269         switch (inode_type(inode) & PROC_VID_MASK) {
270                 case PROC_XID_INO:
271                         hashed = xid_is_hashed(vid);
272                         break;
273                 case PROC_NID_INO:
274                         hashed = nid_is_hashed(vid);
275                         break;
276         }
277         if (hashed)
278                 return 1;
279         d_drop(dentry);
280         return 0;
281 }
282
283 /*
284 static int proc_vid_delete_dentry(struct dentry * dentry)
285 {
286         return 1;
287 }
288 */
289
290
291 #define PROC_BLOCK_SIZE (PAGE_SIZE - 1024)
292
293 static ssize_t proc_vid_info_read(struct file * file, char * buf,
294                           size_t count, loff_t *ppos)
295 {
296         struct inode * inode = file->f_dentry->d_inode;
297         unsigned long page;
298         ssize_t length;
299         int vid;
300
301         if (count > PROC_BLOCK_SIZE)
302                 count = PROC_BLOCK_SIZE;
303         if (!(page = __get_free_page(GFP_KERNEL)))
304                 return -ENOMEM;
305
306         vid = inode_vid(inode);
307         length = PROC_I(inode)->op.proc_vid_read(vid, (char*)page);
308
309         if (length >= 0)
310                 length = simple_read_from_buffer(buf, count, ppos,
311                         (char *)page, length);
312         free_page(page);
313         return length;
314 }
315
316
317
318
319
320 /* here comes the lower level (vid) */
321
322 static struct file_operations proc_vid_info_file_operations = {
323         read:           proc_vid_info_read,
324 };
325
326 static struct dentry_operations proc_vid_dentry_operations = {
327         d_revalidate:   proc_vid_revalidate,
328 //      d_delete:       proc_vid_delete_dentry,
329 };
330
331
332 struct vid_entry {
333         int type;
334         int len;
335         char *name;
336         mode_t mode;
337 };
338
339 #define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
340
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),
348         {0,0,NULL,0}
349 };
350
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),
354         {0,0,NULL,0}
355 };
356
357
358
359 static struct dentry *proc_vid_lookup(struct inode *dir,
360         struct dentry *dentry, struct nameidata *nd)
361 {
362         struct inode *inode;
363         struct vid_entry *p;
364         int error;
365
366         error = -ENOENT;
367         inode = NULL;
368
369         switch (inode_type(dir)) {
370                 case PROC_XID_INO:
371                         p = vx_base_stuff;
372                         break;
373                 case PROC_NID_INO:
374                         p = vn_base_stuff;
375                         break;
376                 default:
377                         goto out;
378         }
379
380         for (; p->name; p++) {
381                 if (p->len != dentry->d_name.len)
382                         continue;
383                 if (!memcmp(dentry->d_name.name, p->name, p->len))
384                         break;
385         }
386         if (!p->name)
387                 goto out;
388
389         error = -EINVAL;
390         inode = proc_vid_make_inode(dir->i_sb, inode_vid(dir), p->type);
391         if (!inode)
392                 goto out;
393
394         switch(p->type) {
395                 case PROC_XID_INFO:
396                         PROC_I(inode)->op.proc_vid_read = proc_xid_info;
397                         break;
398                 case PROC_XID_STATUS:
399                         PROC_I(inode)->op.proc_vid_read = proc_xid_status;
400                         break;
401                 case PROC_XID_LIMIT:
402                         PROC_I(inode)->op.proc_vid_read = proc_xid_limit;
403                         break;
404                 case PROC_XID_SCHED:
405                         PROC_I(inode)->op.proc_vid_read = proc_xid_sched;
406                         break;
407                 case PROC_XID_CVIRT:
408                         PROC_I(inode)->op.proc_vid_read = proc_xid_cvirt;
409                         break;
410                 case PROC_XID_CACCT:
411                         PROC_I(inode)->op.proc_vid_read = proc_xid_cacct;
412                         break;
413
414                 case PROC_NID_INFO:
415                         PROC_I(inode)->op.proc_vid_read = proc_nid_info;
416                         break;
417                 case PROC_NID_STATUS:
418                         PROC_I(inode)->op.proc_vid_read = proc_nid_status;
419                         break;
420
421                 default:
422                         printk("procfs: impossible type (%d)",p->type);
423                         iput(inode);
424                         return ERR_PTR(-EINVAL);
425         }
426         inode->i_mode = p->mode;
427 //      inode->i_op = &proc_vid_info_inode_operations;
428         inode->i_fop = &proc_vid_info_file_operations;
429         inode->i_nlink = 1;
430         inode->i_flags|=S_IMMUTABLE;
431
432         dentry->d_op = &proc_vid_dentry_operations;
433         d_add(dentry, inode);
434         error = 0;
435 out:
436         return ERR_PTR(error);
437 }
438
439
440 static int proc_vid_readdir(struct file * filp,
441         void * dirent, filldir_t filldir)
442 {
443         int i, size;
444         struct inode *inode = filp->f_dentry->d_inode;
445         struct vid_entry *p;
446
447         i = filp->f_pos;
448         switch (i) {
449                 case 0:
450                         if (filldir(dirent, ".", 1, i,
451                                 inode->i_ino, DT_DIR) < 0)
452                                 return 0;
453                         i++;
454                         filp->f_pos++;
455                         /* fall through */
456                 case 1:
457                         if (filldir(dirent, "..", 2, i,
458                                 PROC_ROOT_INO, DT_DIR) < 0)
459                                 return 0;
460                         i++;
461                         filp->f_pos++;
462                         /* fall through */
463                 default:
464                         i -= 2;
465                         switch (inode_type(inode)) {
466                                 case PROC_XID_INO:
467                                         size = sizeof(vx_base_stuff);
468                                         p = vx_base_stuff + i;
469                                         break;
470                                 case PROC_NID_INO:
471                                         size = sizeof(vn_base_stuff);
472                                         p = vn_base_stuff + i;
473                                         break;
474                                 default:
475                                         return 1;
476                         }
477                         if (i >= size/sizeof(struct vid_entry))
478                                 return 1;
479                         while (p->name) {
480                                 if (filldir(dirent, p->name, p->len,
481                                         filp->f_pos, fake_ino(inode_vid(inode),
482                                         p->type), p->mode >> 12) < 0)
483                                         return 0;
484                                 filp->f_pos++;
485                                 p++;
486                         }
487         }
488         return 1;
489 }
490
491
492
493
494 /* now the upper level (virtual) */
495
496 static struct file_operations proc_vid_file_operations = {
497         read:           generic_read_dir,
498         readdir:        proc_vid_readdir,
499 };
500
501 static struct inode_operations proc_vid_inode_operations = {
502         lookup:         proc_vid_lookup,
503 };
504
505
506
507 static __inline__ int atovid(const char *str, int len)
508 {
509         int vid, c;
510
511         vid = 0;
512         while (len-- > 0) {
513                 c = *str - '0';
514                 str++;
515                 if (c > 9)
516                         return -1;
517                 if (vid >= MAX_MULBY10)
518                         return -1;
519                 vid *= 10;
520                 vid += c;
521                 if (!vid)
522                         return -1;
523         }
524         return vid;
525 }
526
527
528 struct dentry *proc_virtual_lookup(struct inode *dir,
529         struct dentry * dentry, struct nameidata *nd)
530 {
531         int xid, len, ret;
532         struct vx_info *vxi;
533         const char *name;
534         struct inode *inode;
535
536         name = dentry->d_name.name;
537         len = dentry->d_name.len;
538         ret = -ENOMEM;
539
540         if (len == 7 && !memcmp(name, "current", 7)) {
541                 inode = new_inode(dir->i_sb);
542                 if (!inode)
543                         goto out;
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;
549                 inode->i_size = 64;
550 //              inode->i_op = &proc_current_inode_operations;
551                 d_add(dentry, inode);
552                 return NULL;
553         }
554         if (len == 4 && !memcmp(name, "info", 4)) {
555                 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_XID_INFO);
556                 if (!inode)
557                         goto out;
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);
564                 return NULL;
565         }
566
567         ret = -ENOENT;
568         xid = atovid(name, len);
569         if (xid < 0)
570                 goto out;
571         vxi = locate_vx_info(xid);
572         if (!vxi)
573                 goto out;
574
575         inode = NULL;
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);
579         if (!inode)
580                 goto out_release;
581
582         inode->i_mode = S_IFDIR|S_IRUGO;
583         inode->i_op = &proc_vid_inode_operations;
584         inode->i_fop = &proc_vid_file_operations;
585         inode->i_nlink = 2;
586         inode->i_flags|=S_IMMUTABLE;
587
588         dentry->d_op = &proc_vid_dentry_operations;
589         d_add(dentry, inode);
590         ret = 0;
591
592 out_release:
593         put_vx_info(vxi);
594 out:
595         return ERR_PTR(ret);
596 }
597
598
599 struct dentry *proc_vnet_lookup(struct inode *dir,
600         struct dentry * dentry, struct nameidata *nd)
601 {
602         int nid, len, ret;
603         struct nx_info *nxi;
604         const char *name;
605         struct inode *inode;
606
607         name = dentry->d_name.name;
608         len = dentry->d_name.len;
609         ret = -ENOMEM;
610         if (len == 7 && !memcmp(name, "current", 7)) {
611                 inode = new_inode(dir->i_sb);
612                 if (!inode)
613                         goto out;
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;
619                 inode->i_size = 64;
620 //              inode->i_op = &proc_current_inode_operations;
621                 d_add(dentry, inode);
622                 return NULL;
623         }
624         if (len == 4 && !memcmp(name, "info", 4)) {
625                 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_NID_INFO);
626                 if (!inode)
627                         goto out;
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);
634                 return NULL;
635         }
636
637         ret = -ENOENT;
638         nid = atovid(name, len);
639         if (nid < 0)
640                 goto out;
641         nxi = locate_nx_info(nid);
642         if (!nxi)
643                 goto out;
644
645         inode = NULL;
646         if (1)
647                 inode = proc_vid_make_inode(dir->i_sb,
648                         nxi->nx_id, PROC_NID_INO);
649         if (!inode)
650                 goto out_release;
651
652         inode->i_mode = S_IFDIR|S_IRUGO;
653         inode->i_op = &proc_vid_inode_operations;
654         inode->i_fop = &proc_vid_file_operations;
655         inode->i_nlink = 2;
656         inode->i_flags|=S_IMMUTABLE;
657
658         dentry->d_op = &proc_vid_dentry_operations;
659         d_add(dentry, inode);
660         ret = 0;
661
662 out_release:
663         put_nx_info(nxi);
664 out:
665         return ERR_PTR(ret);
666 }
667
668
669
670
671 #define PROC_NUMBUF 10
672 #define PROC_MAXVIDS 32
673
674 int proc_virtual_readdir(struct file * filp,
675         void * dirent, filldir_t filldir)
676 {
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;
681         ino_t ino;
682
683         switch ((long)filp->f_pos) {
684                 case 0:
685                         ino = fake_ino(0, PROC_XID_INO);
686                         if (filldir(dirent, ".", 1,
687                                 filp->f_pos, ino, DT_DIR) < 0)
688                                 return 0;
689                         filp->f_pos++;
690                         /* fall through */
691                 case 1:
692                         ino = filp->f_dentry->d_parent->d_inode->i_ino;
693                         if (filldir(dirent, "..", 2,
694                                 filp->f_pos, ino, DT_DIR) < 0)
695                                 return 0;
696                         filp->f_pos++;
697                         /* fall through */
698                 case 2:
699                         ino = fake_ino(0, PROC_XID_INFO);
700                         if (filldir(dirent, "info", 4,
701                                 filp->f_pos, ino, DT_LNK) < 0)
702                                 return 0;
703                         filp->f_pos++;
704                         /* fall through */
705                 case 3:
706                         if (vx_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)
710                                         return 0;
711                         }
712                         filp->f_pos++;
713         }
714
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;
720
721                 do buf[--j] = '0' + (xid % 10); while (xid/=10);
722
723                 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
724                         filp->f_pos, ino, DT_DIR) < 0)
725                         break;
726                 filp->f_pos++;
727         }
728         return 0;
729 }
730
731
732 static struct file_operations proc_virtual_dir_operations = {
733         read:           generic_read_dir,
734         readdir:        proc_virtual_readdir,
735 };
736
737 static struct inode_operations proc_virtual_dir_inode_operations = {
738         lookup:         proc_virtual_lookup,
739 };
740
741
742 int proc_vnet_readdir(struct file * filp,
743         void * dirent, filldir_t filldir)
744 {
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;
749         ino_t ino;
750
751         switch ((long)filp->f_pos) {
752                 case 0:
753                         ino = fake_ino(0, PROC_NID_INO);
754                         if (filldir(dirent, ".", 1,
755                                 filp->f_pos, ino, DT_DIR) < 0)
756                                 return 0;
757                         filp->f_pos++;
758                         /* fall through */
759                 case 1:
760                         ino = filp->f_dentry->d_parent->d_inode->i_ino;
761                         if (filldir(dirent, "..", 2,
762                                 filp->f_pos, ino, DT_DIR) < 0)
763                                 return 0;
764                         filp->f_pos++;
765                         /* fall through */
766                 case 2:
767                         ino = fake_ino(0, PROC_NID_INFO);
768                         if (filldir(dirent, "info", 4,
769                                 filp->f_pos, ino, DT_LNK) < 0)
770                                 return 0;
771                         filp->f_pos++;
772                         /* fall through */
773                 case 3:
774                         if (vx_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)
778                                         return 0;
779                         }
780                         filp->f_pos++;
781         }
782
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;
788
789                 do buf[--j] = '0' + (nid % 10); while (nid/=10);
790
791                 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
792                         filp->f_pos, ino, DT_DIR) < 0)
793                         break;
794                 filp->f_pos++;
795         }
796         return 0;
797 }
798
799
800 static struct file_operations proc_vnet_dir_operations = {
801         read:           generic_read_dir,
802         readdir:        proc_vnet_readdir,
803 };
804
805 static struct inode_operations proc_vnet_dir_inode_operations = {
806         lookup:         proc_vnet_lookup,
807 };
808
809
810
811 void proc_vx_init(void)
812 {
813         struct proc_dir_entry *ent;
814
815         ent = proc_mkdir("virtual", 0);
816         if (ent) {
817                 ent->proc_fops = &proc_virtual_dir_operations;
818                 ent->proc_iops = &proc_virtual_dir_inode_operations;
819         }
820         proc_virtual = ent;
821
822         ent = proc_mkdir("virtnet", 0);
823         if (ent) {
824                 ent->proc_fops = &proc_vnet_dir_operations;
825                 ent->proc_iops = &proc_vnet_dir_inode_operations;
826         }
827         proc_vnet = ent;
828 }
829
830
831
832
833 /* per pid info */
834
835
836 int proc_pid_vx_info(struct task_struct *p, char *buffer)
837 {
838         struct vx_info *vxi;
839         char * orig = buffer;
840
841         buffer += sprintf (buffer,"XID:\t%d\n", vx_task_xid(p));
842         vxi = task_get_vx_info(p);
843         if (vxi && !vx_flags(VXF_INFO_HIDE, 0)) {
844                 buffer += sprintf (buffer,"BCaps:\t%016llx\n"
845                         ,(unsigned long long)vxi->vx_bcaps);
846                 buffer += sprintf (buffer,"CCaps:\t%016llx\n"
847                         ,(unsigned long long)vxi->vx_ccaps);
848                 buffer += sprintf (buffer,"CFlags:\t%016llx\n"
849                         ,(unsigned long long)vxi->vx_flags);
850                 buffer += sprintf (buffer,"CIPid:\t%d\n"
851                         ,vxi->vx_initpid);
852         }
853         put_vx_info(vxi);
854         return buffer - orig;
855 }
856
857
858 int proc_pid_nx_info(struct task_struct *p, char *buffer)
859 {
860         struct nx_info *nxi;
861         char * orig = buffer;
862
863         buffer += sprintf (buffer,"NID:\t%d\n", nx_task_nid(p));
864         nxi = task_get_nx_info(p);
865         if (nxi && !vx_flags(VXF_INFO_HIDE, 0)) {
866                 int i;
867
868                 for (i=0; i<nxi->nbipv4; i++){
869                         buffer += sprintf (buffer,
870                                 "V4Root[%d]:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i
871                                 ,NIPQUAD(nxi->ipv4[i])
872                                 ,NIPQUAD(nxi->mask[i]));
873                 }
874                 buffer += sprintf (buffer,
875                         "V4Root[bcast]:\t%d.%d.%d.%d\n"
876                         ,NIPQUAD(nxi->v4_bcast));
877         }
878         put_nx_info(nxi);
879         return buffer - orig;
880 }
881