patch-2.6.6-vs1.9.1
[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
23 #include <asm/uaccess.h>
24 #include <asm/unistd.h>
25
26
27 static struct proc_dir_entry *proc_virtual;
28
29 static struct proc_dir_entry *proc_vnet;
30
31
32 enum vid_directory_inos {
33         PROC_XID_INO = 32,
34         PROC_XID_INFO,
35         PROC_XID_STATUS,
36         PROC_XID_LIMIT,
37         PROC_XID_SCHED,
38         PROC_XID_CVIRT,
39         PROC_XID_CACCT,
40
41         PROC_NID_INO = 64,
42         PROC_NID_INFO,
43         PROC_NID_STATUS,
44 };
45
46 #define PROC_VID_MASK   0x60
47
48
49 /* first the actual feeds */
50
51
52 static int proc_virtual_info(int vid, char *buffer)
53 {
54         return sprintf(buffer,
55                 "VCIVersion:\t%04x:%04x\n"
56                 "VCISyscall:\t%d\n"
57                 ,VCI_VERSION >> 16
58                 ,VCI_VERSION & 0xFFFF
59                 ,__NR_vserver
60                 );
61 }
62
63
64 int proc_xid_info (int vid, char *buffer)
65 {
66         struct vx_info *vxi;
67         int length;
68
69         vxi = locate_vx_info(vid);
70         if (!vxi)
71                 return 0;
72         length = sprintf(buffer,
73                 "ID:\t%d\n"
74                 "Info:\t%p\n"
75                 "Init:\t%d\n"
76                 ,vxi->vx_id
77                 ,vxi
78                 ,vxi->vx_initpid
79                 );
80         put_vx_info(vxi);
81         return length;
82 }
83
84 int proc_xid_status (int vid, char *buffer)
85 {
86         struct vx_info *vxi;
87         int length;
88
89         vxi = locate_vx_info(vid);
90         if (!vxi)
91                 return 0;
92         length = sprintf(buffer,
93                 "UseCnt:\t%d\n"         
94                 "RefCnt:\t%d\n"         
95                 "Flags:\t%016llx\n"
96                 "BCaps:\t%016llx\n"
97                 "CCaps:\t%016llx\n"
98                 "Ticks:\t%d\n"          
99                 ,atomic_read(&vxi->vx_usecnt)
100                 ,atomic_read(&vxi->vx_refcnt)
101                 ,(unsigned long long)vxi->vx_flags
102                 ,(unsigned long long)vxi->vx_bcaps
103                 ,(unsigned long long)vxi->vx_ccaps
104                 ,atomic_read(&vxi->limit.ticks)
105                 );
106         put_vx_info(vxi);
107         return length;
108 }
109
110 int proc_xid_limit (int vid, char *buffer)
111 {
112         struct vx_info *vxi;
113         int length;
114
115         vxi = locate_vx_info(vid);
116         if (!vxi)
117                 return 0;
118         length = vx_info_proc_limit(&vxi->limit, buffer);
119         put_vx_info(vxi);
120         return length;
121 }
122
123 int proc_xid_sched (int vid, char *buffer)
124 {
125         struct vx_info *vxi;
126         int length;
127
128         vxi = locate_vx_info(vid);
129         if (!vxi)
130                 return 0;
131         length = vx_info_proc_sched(&vxi->sched, buffer);
132         put_vx_info(vxi);
133         return length;
134 }
135
136 int proc_xid_cvirt (int vid, char *buffer)
137 {
138         struct vx_info *vxi;
139         int length;
140
141         vxi = locate_vx_info(vid);
142         if (!vxi)
143                 return 0;
144         length = vx_info_proc_cvirt(&vxi->cvirt, buffer);
145         put_vx_info(vxi);
146         return length;
147 }
148
149 int proc_xid_cacct (int vid, char *buffer)
150 {
151         struct vx_info *vxi;
152         int length;
153
154         vxi = locate_vx_info(vid);
155         if (!vxi)
156                 return 0;
157         length = vx_info_proc_cacct(&vxi->cacct, buffer);
158         put_vx_info(vxi);
159         return length;
160 }
161
162
163 static int proc_vnet_info(int vid, char *buffer)
164 {
165         return sprintf(buffer,
166                 "VCIVersion:\t%04x:%04x\n"
167                 "VCISyscall:\t%d\n"
168                 ,VCI_VERSION >> 16
169                 ,VCI_VERSION & 0xFFFF
170                 ,__NR_vserver
171                 );
172 }
173
174 #define atoquad(a) \
175         (((a)>>0) & 0xff), (((a)>>8) & 0xff), \
176         (((a)>>16) & 0xff), (((a)>>24) & 0xff)
177
178 int proc_nid_info (int vid, char *buffer)
179 {
180         struct nx_info *nxi;
181         int length, i;
182
183         nxi = locate_nx_info(vid);
184         if (!nxi)
185                 return 0;
186         length = sprintf(buffer,
187                 "ID:\t%d\n"
188                 "Info:\t%p\n"
189                 ,nxi->nx_id
190                 ,nxi
191                 );
192         for (i=0; i<nxi->nbipv4; i++) {
193                 length += sprintf(buffer + length,
194                         "%d:\t%d.%d.%d.%d/%d.%d.%d.%d\n", i,
195                         atoquad(nxi->ipv4[i]),
196                         atoquad(nxi->mask[i]));
197         }
198         put_nx_info(nxi);
199         return length;
200 }
201
202 int proc_nid_status (int vid, char *buffer)
203 {
204         struct nx_info *nxi;
205         int length;
206
207         nxi = locate_nx_info(vid);
208         if (!nxi)
209                 return 0;
210         length = sprintf(buffer,
211                 "UseCnt:\t%d\n"         
212                 "RefCnt:\t%d\n"         
213                 ,atomic_read(&nxi->nx_usecnt)
214                 ,atomic_read(&nxi->nx_refcnt)
215                 );
216         put_nx_info(nxi);
217         return length;
218 }
219
220 /* here the inode helpers */
221
222
223
224 #define fake_ino(id,ino) (((id)<<16)|(ino))
225
226 #define inode_vid(i)    ((i)->i_ino >> 16)
227 #define inode_type(i)   ((i)->i_ino & 0xFFFF)
228
229 #define MAX_MULBY10     ((~0U-9)/10)
230
231
232 static struct inode *proc_vid_make_inode(struct super_block * sb,
233         int vid, int ino)
234 {
235         struct inode *inode = new_inode(sb);
236
237         if (!inode)
238                 goto out;
239
240         inode->i_mtime = inode->i_atime =
241                 inode->i_ctime = CURRENT_TIME;
242         inode->i_ino = fake_ino(vid, ino);
243
244         inode->i_uid = 0;
245         inode->i_gid = 0;
246         // inode->i_xid = xid;
247 out:
248         return inode;
249 }
250
251 static int proc_vid_revalidate(struct dentry * dentry, struct nameidata *nd)
252 {
253         struct inode * inode = dentry->d_inode;
254         int vid, hashed=0;
255
256         vid = inode_vid(inode);
257         switch (inode_type(inode) & PROC_VID_MASK) {
258                 case PROC_XID_INO:
259                         hashed = vx_info_is_hashed(vid);
260                         break;
261                 case PROC_NID_INO:
262                         hashed = nx_info_is_hashed(vid);
263                         break;
264         }       
265         if (hashed)
266                 return 1;
267         d_drop(dentry);
268         return 0;
269 }
270
271 /*
272 static int proc_vid_delete_dentry(struct dentry * dentry)
273 {
274         return 1;
275 }
276 */
277
278
279 #define PROC_BLOCK_SIZE (PAGE_SIZE - 1024)
280
281 static ssize_t proc_vid_info_read(struct file * file, char * buf,
282                           size_t count, loff_t *ppos)
283 {
284         struct inode * inode = file->f_dentry->d_inode;
285         unsigned long page;
286         ssize_t length;
287         ssize_t end;
288         int vid;
289
290         if (count > PROC_BLOCK_SIZE)
291                 count = PROC_BLOCK_SIZE;
292         if (!(page = __get_free_page(GFP_KERNEL)))
293                 return -ENOMEM;
294
295         vid = inode_vid(inode);
296         length = PROC_I(inode)->op.proc_vid_read(vid, (char*)page);
297
298         if (length < 0) {
299                 free_page(page);
300                 return length;
301         }
302         /* Static 4kB (or whatever) block capacity */
303         if (*ppos >= length) {
304                 free_page(page);
305                 return 0;
306         }
307         if (count + *ppos > length)
308                 count = length - *ppos;
309         end = count + *ppos;
310         copy_to_user(buf, (char *) page + *ppos, count);
311         *ppos = end;
312         free_page(page);
313         return count;
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 (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 (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("vnet", 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 char *task_vx_info(struct task_struct *p, char *buffer)
837 {
838         return buffer + sprintf(buffer,
839                 "XID:\t%d\n"
840                 ,p->xid);
841 }
842
843 int proc_pid_vx_info(struct task_struct *p, char *buffer)
844 {
845         char * orig = buffer;
846
847         buffer = task_vx_info(p, buffer);
848         return buffer - orig;
849 }
850
851 char *task_nx_info(struct task_struct *p, char *buffer)
852 {
853         return buffer + sprintf(buffer,
854                 "NID:\t%d\n"
855                 ,p->nid);
856 }
857
858 int proc_pid_nx_info(struct task_struct *p, char *buffer)
859 {
860         char * orig = buffer;
861
862         buffer = task_nx_info(p, buffer);
863         return buffer - orig;
864 }
865