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