vserver 2.0-rc4
[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                 "Tasks:\t%d\n"
225                 ,atomic_read(&nxi->nx_usecnt)
226                 ,atomic_read(&nxi->nx_tasks)
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 out:
259         return inode;
260 }
261
262 static int proc_vid_revalidate(struct dentry * dentry, struct nameidata *nd)
263 {
264         struct inode * inode = dentry->d_inode;
265         int vid, hashed=0;
266
267         vid = inode_vid(inode);
268         switch (inode_type(inode) & PROC_VID_MASK) {
269                 case PROC_XID_INO:
270                         hashed = xid_is_hashed(vid);
271                         break;
272                 case PROC_NID_INO:
273                         hashed = nid_is_hashed(vid);
274                         break;
275         }
276         if (hashed)
277                 return 1;
278         d_drop(dentry);
279         return 0;
280 }
281
282
283 #define PROC_BLOCK_SIZE (PAGE_SIZE - 1024)
284
285 static ssize_t proc_vid_info_read(struct file * file, char * buf,
286                           size_t count, loff_t *ppos)
287 {
288         struct inode * inode = file->f_dentry->d_inode;
289         unsigned long page;
290         ssize_t length;
291         int vid;
292
293         if (count > PROC_BLOCK_SIZE)
294                 count = PROC_BLOCK_SIZE;
295         if (!(page = __get_free_page(GFP_KERNEL)))
296                 return -ENOMEM;
297
298         vid = inode_vid(inode);
299         length = PROC_I(inode)->op.proc_vid_read(vid, (char*)page);
300
301         if (length >= 0)
302                 length = simple_read_from_buffer(buf, count, ppos,
303                         (char *)page, length);
304         free_page(page);
305         return length;
306 }
307
308
309
310
311
312 /* here comes the lower level (vid) */
313
314 static struct file_operations proc_vid_info_file_operations = {
315         read:           proc_vid_info_read,
316 };
317
318 static struct dentry_operations proc_vid_dentry_operations = {
319         d_revalidate:   proc_vid_revalidate,
320 };
321
322
323 struct vid_entry {
324         int type;
325         int len;
326         char *name;
327         mode_t mode;
328 };
329
330 #define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
331
332 static struct vid_entry vx_base_stuff[] = {
333         E(PROC_XID_INFO,        "info",         S_IFREG|S_IRUGO),
334         E(PROC_XID_STATUS,      "status",       S_IFREG|S_IRUGO),
335         E(PROC_XID_LIMIT,       "limit",        S_IFREG|S_IRUGO),
336         E(PROC_XID_SCHED,       "sched",        S_IFREG|S_IRUGO),
337         E(PROC_XID_CVIRT,       "cvirt",        S_IFREG|S_IRUGO),
338         E(PROC_XID_CACCT,       "cacct",        S_IFREG|S_IRUGO),
339         {0,0,NULL,0}
340 };
341
342 static struct vid_entry vn_base_stuff[] = {
343         E(PROC_NID_INFO,        "info",         S_IFREG|S_IRUGO),
344         E(PROC_NID_STATUS,      "status",       S_IFREG|S_IRUGO),
345         {0,0,NULL,0}
346 };
347
348
349
350 static struct dentry *proc_vid_lookup(struct inode *dir,
351         struct dentry *dentry, struct nameidata *nd)
352 {
353         struct inode *inode;
354         struct vid_entry *p;
355         int error;
356
357         error = -ENOENT;
358         inode = NULL;
359
360         switch (inode_type(dir)) {
361                 case PROC_XID_INO:
362                         p = vx_base_stuff;
363                         break;
364                 case PROC_NID_INO:
365                         p = vn_base_stuff;
366                         break;
367                 default:
368                         goto out;
369         }
370
371         for (; p->name; p++) {
372                 if (p->len != dentry->d_name.len)
373                         continue;
374                 if (!memcmp(dentry->d_name.name, p->name, p->len))
375                         break;
376         }
377         if (!p->name)
378                 goto out;
379
380         error = -EINVAL;
381         inode = proc_vid_make_inode(dir->i_sb, inode_vid(dir), p->type);
382         if (!inode)
383                 goto out;
384
385         switch(p->type) {
386                 case PROC_XID_INFO:
387                         PROC_I(inode)->op.proc_vid_read = proc_xid_info;
388                         break;
389                 case PROC_XID_STATUS:
390                         PROC_I(inode)->op.proc_vid_read = proc_xid_status;
391                         break;
392                 case PROC_XID_LIMIT:
393                         PROC_I(inode)->op.proc_vid_read = proc_xid_limit;
394                         break;
395                 case PROC_XID_SCHED:
396                         PROC_I(inode)->op.proc_vid_read = proc_xid_sched;
397                         break;
398                 case PROC_XID_CVIRT:
399                         PROC_I(inode)->op.proc_vid_read = proc_xid_cvirt;
400                         break;
401                 case PROC_XID_CACCT:
402                         PROC_I(inode)->op.proc_vid_read = proc_xid_cacct;
403                         break;
404
405                 case PROC_NID_INFO:
406                         PROC_I(inode)->op.proc_vid_read = proc_nid_info;
407                         break;
408                 case PROC_NID_STATUS:
409                         PROC_I(inode)->op.proc_vid_read = proc_nid_status;
410                         break;
411
412                 default:
413                         printk("procfs: impossible type (%d)",p->type);
414                         iput(inode);
415                         return ERR_PTR(-EINVAL);
416         }
417         inode->i_mode = p->mode;
418         inode->i_fop = &proc_vid_info_file_operations;
419         inode->i_nlink = 1;
420         inode->i_flags|=S_IMMUTABLE;
421
422         dentry->d_op = &proc_vid_dentry_operations;
423         d_add(dentry, inode);
424         error = 0;
425 out:
426         return ERR_PTR(error);
427 }
428
429
430 static int proc_vid_readdir(struct file * filp,
431         void * dirent, filldir_t filldir)
432 {
433         int i, size;
434         struct inode *inode = filp->f_dentry->d_inode;
435         struct vid_entry *p;
436
437         i = filp->f_pos;
438         switch (i) {
439                 case 0:
440                         if (filldir(dirent, ".", 1, i,
441                                 inode->i_ino, DT_DIR) < 0)
442                                 return 0;
443                         i++;
444                         filp->f_pos++;
445                         /* fall through */
446                 case 1:
447                         if (filldir(dirent, "..", 2, i,
448                                 PROC_ROOT_INO, DT_DIR) < 0)
449                                 return 0;
450                         i++;
451                         filp->f_pos++;
452                         /* fall through */
453                 default:
454                         i -= 2;
455                         switch (inode_type(inode)) {
456                                 case PROC_XID_INO:
457                                         size = sizeof(vx_base_stuff);
458                                         p = vx_base_stuff + i;
459                                         break;
460                                 case PROC_NID_INO:
461                                         size = sizeof(vn_base_stuff);
462                                         p = vn_base_stuff + i;
463                                         break;
464                                 default:
465                                         return 1;
466                         }
467                         if (i >= size/sizeof(struct vid_entry))
468                                 return 1;
469                         while (p->name) {
470                                 if (filldir(dirent, p->name, p->len,
471                                         filp->f_pos, fake_ino(inode_vid(inode),
472                                         p->type), p->mode >> 12) < 0)
473                                         return 0;
474                                 filp->f_pos++;
475                                 p++;
476                         }
477         }
478         return 1;
479 }
480
481
482
483
484 /* now the upper level (virtual) */
485
486 static struct file_operations proc_vid_file_operations = {
487         read:           generic_read_dir,
488         readdir:        proc_vid_readdir,
489 };
490
491 static struct inode_operations proc_vid_inode_operations = {
492         lookup:         proc_vid_lookup,
493 };
494
495
496
497 static __inline__ int atovid(const char *str, int len)
498 {
499         int vid, c;
500
501         vid = 0;
502         while (len-- > 0) {
503                 c = *str - '0';
504                 str++;
505                 if (c > 9)
506                         return -1;
507                 if (vid >= MAX_MULBY10)
508                         return -1;
509                 vid *= 10;
510                 vid += c;
511                 if (!vid)
512                         return -1;
513         }
514         return vid;
515 }
516
517
518 struct dentry *proc_virtual_lookup(struct inode *dir,
519         struct dentry * dentry, struct nameidata *nd)
520 {
521         int xid, len, ret;
522         struct vx_info *vxi;
523         const char *name;
524         struct inode *inode;
525
526         name = dentry->d_name.name;
527         len = dentry->d_name.len;
528         ret = -ENOMEM;
529
530         if (len == 7 && !memcmp(name, "current", 7)) {
531                 inode = new_inode(dir->i_sb);
532                 if (!inode)
533                         goto out;
534                 inode->i_mtime = inode->i_atime =
535                         inode->i_ctime = CURRENT_TIME;
536                 inode->i_ino = fake_ino(1, PROC_XID_INO);
537                 inode->i_mode = S_IFLNK|S_IRWXUGO;
538                 inode->i_uid = inode->i_gid = 0;
539                 d_add(dentry, inode);
540                 return NULL;
541         }
542         if (len == 4 && !memcmp(name, "info", 4)) {
543                 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_XID_INFO);
544                 if (!inode)
545                         goto out;
546                 inode->i_fop = &proc_vid_info_file_operations;
547                 PROC_I(inode)->op.proc_vid_read = proc_virtual_info;
548                 inode->i_mode = S_IFREG|S_IRUGO;
549                 d_add(dentry, inode);
550                 return NULL;
551         }
552
553         ret = -ENOENT;
554         xid = atovid(name, len);
555         if (xid < 0)
556                 goto out;
557         vxi = locate_vx_info(xid);
558         if (!vxi)
559                 goto out;
560
561         inode = NULL;
562         if (vx_check(xid, VX_ADMIN|VX_WATCH|VX_IDENT))
563                 inode = proc_vid_make_inode(dir->i_sb,
564                         vxi->vx_id, PROC_XID_INO);
565         if (!inode)
566                 goto out_release;
567
568         inode->i_mode = S_IFDIR|S_IRUGO;
569         inode->i_op = &proc_vid_inode_operations;
570         inode->i_fop = &proc_vid_file_operations;
571         inode->i_nlink = 2;
572         inode->i_flags|=S_IMMUTABLE;
573
574         dentry->d_op = &proc_vid_dentry_operations;
575         d_add(dentry, inode);
576         ret = 0;
577
578 out_release:
579         put_vx_info(vxi);
580 out:
581         return ERR_PTR(ret);
582 }
583
584
585 struct dentry *proc_vnet_lookup(struct inode *dir,
586         struct dentry * dentry, struct nameidata *nd)
587 {
588         int nid, len, ret;
589         struct nx_info *nxi;
590         const char *name;
591         struct inode *inode;
592
593         name = dentry->d_name.name;
594         len = dentry->d_name.len;
595         ret = -ENOMEM;
596         if (len == 7 && !memcmp(name, "current", 7)) {
597                 inode = new_inode(dir->i_sb);
598                 if (!inode)
599                         goto out;
600                 inode->i_mtime = inode->i_atime =
601                         inode->i_ctime = CURRENT_TIME;
602                 inode->i_ino = fake_ino(1, PROC_NID_INO);
603                 inode->i_mode = S_IFLNK|S_IRWXUGO;
604                 inode->i_uid = inode->i_gid = 0;
605                 d_add(dentry, inode);
606                 return NULL;
607         }
608         if (len == 4 && !memcmp(name, "info", 4)) {
609                 inode = proc_vid_make_inode(dir->i_sb, 0, PROC_NID_INFO);
610                 if (!inode)
611                         goto out;
612                 inode->i_fop = &proc_vid_info_file_operations;
613                 PROC_I(inode)->op.proc_vid_read = proc_vnet_info;
614                 inode->i_mode = S_IFREG|S_IRUGO;
615                 d_add(dentry, inode);
616                 return NULL;
617         }
618
619         ret = -ENOENT;
620         nid = atovid(name, len);
621         if (nid < 0)
622                 goto out;
623         nxi = locate_nx_info(nid);
624         if (!nxi)
625                 goto out;
626
627         inode = NULL;
628         if (1)
629                 inode = proc_vid_make_inode(dir->i_sb,
630                         nxi->nx_id, PROC_NID_INO);
631         if (!inode)
632                 goto out_release;
633
634         inode->i_mode = S_IFDIR|S_IRUGO;
635         inode->i_op = &proc_vid_inode_operations;
636         inode->i_fop = &proc_vid_file_operations;
637         inode->i_nlink = 2;
638         inode->i_flags|=S_IMMUTABLE;
639
640         dentry->d_op = &proc_vid_dentry_operations;
641         d_add(dentry, inode);
642         ret = 0;
643
644 out_release:
645         put_nx_info(nxi);
646 out:
647         return ERR_PTR(ret);
648 }
649
650
651
652
653 #define PROC_NUMBUF 10
654 #define PROC_MAXVIDS 32
655
656 int proc_virtual_readdir(struct file * filp,
657         void * dirent, filldir_t filldir)
658 {
659         unsigned int xid_array[PROC_MAXVIDS];
660         char buf[PROC_NUMBUF];
661         unsigned int nr = filp->f_pos-3;
662         unsigned int nr_xids, i;
663         ino_t ino;
664
665         switch ((long)filp->f_pos) {
666                 case 0:
667                         ino = fake_ino(0, PROC_XID_INO);
668                         if (filldir(dirent, ".", 1,
669                                 filp->f_pos, ino, DT_DIR) < 0)
670                                 return 0;
671                         filp->f_pos++;
672                         /* fall through */
673                 case 1:
674                         ino = filp->f_dentry->d_parent->d_inode->i_ino;
675                         if (filldir(dirent, "..", 2,
676                                 filp->f_pos, ino, DT_DIR) < 0)
677                                 return 0;
678                         filp->f_pos++;
679                         /* fall through */
680                 case 2:
681                         ino = fake_ino(0, PROC_XID_INFO);
682                         if (filldir(dirent, "info", 4,
683                                 filp->f_pos, ino, DT_LNK) < 0)
684                                 return 0;
685                         filp->f_pos++;
686                         /* fall through */
687                 case 3:
688                         if (vx_current_xid() > 1) {
689                                 ino = fake_ino(1, PROC_XID_INO);
690                                 if (filldir(dirent, "current", 7,
691                                         filp->f_pos, ino, DT_LNK) < 0)
692                                         return 0;
693                         }
694                         filp->f_pos++;
695         }
696
697         nr_xids = get_xid_list(nr, xid_array, PROC_MAXVIDS);
698         for (i = 0; i < nr_xids; i++) {
699                 int xid = xid_array[i];
700                 ino_t ino = fake_ino(xid, PROC_XID_INO);
701                 unsigned int j = PROC_NUMBUF;
702
703                 do buf[--j] = '0' + (xid % 10); while (xid/=10);
704
705                 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
706                         filp->f_pos, ino, DT_DIR) < 0)
707                         break;
708                 filp->f_pos++;
709         }
710         return 0;
711 }
712
713
714 static struct file_operations proc_virtual_dir_operations = {
715         read:           generic_read_dir,
716         readdir:        proc_virtual_readdir,
717 };
718
719 static struct inode_operations proc_virtual_dir_inode_operations = {
720         lookup:         proc_virtual_lookup,
721 };
722
723
724 int proc_vnet_readdir(struct file * filp,
725         void * dirent, filldir_t filldir)
726 {
727         unsigned int nid_array[PROC_MAXVIDS];
728         char buf[PROC_NUMBUF];
729         unsigned int nr = filp->f_pos-3;
730         unsigned int nr_nids, i;
731         ino_t ino;
732
733         switch ((long)filp->f_pos) {
734                 case 0:
735                         ino = fake_ino(0, PROC_NID_INO);
736                         if (filldir(dirent, ".", 1,
737                                 filp->f_pos, ino, DT_DIR) < 0)
738                                 return 0;
739                         filp->f_pos++;
740                         /* fall through */
741                 case 1:
742                         ino = filp->f_dentry->d_parent->d_inode->i_ino;
743                         if (filldir(dirent, "..", 2,
744                                 filp->f_pos, ino, DT_DIR) < 0)
745                                 return 0;
746                         filp->f_pos++;
747                         /* fall through */
748                 case 2:
749                         ino = fake_ino(0, PROC_NID_INFO);
750                         if (filldir(dirent, "info", 4,
751                                 filp->f_pos, ino, DT_LNK) < 0)
752                                 return 0;
753                         filp->f_pos++;
754                         /* fall through */
755                 case 3:
756                         if (vx_current_xid() > 1) {
757                                 ino = fake_ino(1, PROC_NID_INO);
758                                 if (filldir(dirent, "current", 7,
759                                         filp->f_pos, ino, DT_LNK) < 0)
760                                         return 0;
761                         }
762                         filp->f_pos++;
763         }
764
765         nr_nids = get_nid_list(nr, nid_array, PROC_MAXVIDS);
766         for (i = 0; i < nr_nids; i++) {
767                 int nid = nid_array[i];
768                 ino_t ino = fake_ino(nid, PROC_NID_INO);
769                 unsigned long j = PROC_NUMBUF;
770
771                 do buf[--j] = '0' + (nid % 10); while (nid/=10);
772
773                 if (filldir(dirent, buf+j, PROC_NUMBUF-j,
774                         filp->f_pos, ino, DT_DIR) < 0)
775                         break;
776                 filp->f_pos++;
777         }
778         return 0;
779 }
780
781
782 static struct file_operations proc_vnet_dir_operations = {
783         read:           generic_read_dir,
784         readdir:        proc_vnet_readdir,
785 };
786
787 static struct inode_operations proc_vnet_dir_inode_operations = {
788         lookup:         proc_vnet_lookup,
789 };
790
791
792
793 void proc_vx_init(void)
794 {
795         struct proc_dir_entry *ent;
796
797         ent = proc_mkdir("virtual", 0);
798         if (ent) {
799                 ent->proc_fops = &proc_virtual_dir_operations;
800                 ent->proc_iops = &proc_virtual_dir_inode_operations;
801         }
802         proc_virtual = ent;
803
804         ent = proc_mkdir("virtnet", 0);
805         if (ent) {
806                 ent->proc_fops = &proc_vnet_dir_operations;
807                 ent->proc_iops = &proc_vnet_dir_inode_operations;
808         }
809         proc_vnet = ent;
810 }
811
812
813
814
815 /* per pid info */
816
817
818 int proc_pid_vx_info(struct task_struct *p, char *buffer)
819 {
820         struct vx_info *vxi;
821         char * orig = buffer;
822
823         buffer += sprintf (buffer,"XID:\t%d\n", vx_task_xid(p));
824         vxi = task_get_vx_info(p);
825         if (vxi && !vx_flags(VXF_INFO_HIDE, 0)) {
826                 buffer += sprintf (buffer,"BCaps:\t%016llx\n"
827                         ,(unsigned long long)vxi->vx_bcaps);
828                 buffer += sprintf (buffer,"CCaps:\t%016llx\n"
829                         ,(unsigned long long)vxi->vx_ccaps);
830                 buffer += sprintf (buffer,"CFlags:\t%016llx\n"
831                         ,(unsigned long long)vxi->vx_flags);
832                 buffer += sprintf (buffer,"CIPid:\t%d\n"
833                         ,vxi->vx_initpid);
834         }
835         put_vx_info(vxi);
836         return buffer - orig;
837 }
838
839
840 int proc_pid_nx_info(struct task_struct *p, char *buffer)
841 {
842         struct nx_info *nxi;
843         char * orig = buffer;
844
845         buffer += sprintf (buffer,"NID:\t%d\n", nx_task_nid(p));
846         nxi = task_get_nx_info(p);
847         if (nxi && !vx_flags(VXF_INFO_HIDE, 0)) {
848                 int i;
849
850                 for (i=0; i<nxi->nbipv4; i++){
851                         buffer += sprintf (buffer,
852                                 "V4Root[%d]:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i
853                                 ,NIPQUAD(nxi->ipv4[i])
854                                 ,NIPQUAD(nxi->mask[i]));
855                 }
856                 buffer += sprintf (buffer,
857                         "V4Root[bcast]:\t%d.%d.%d.%d\n"
858                         ,NIPQUAD(nxi->v4_bcast));
859         }
860         put_nx_info(nxi);
861         return buffer - orig;
862 }
863