procfs_vnops.c revision 1.13 1 /*
2 * Copyright (c) 1993 The Regents of the University of California.
3 * Copyright (c) 1993 Jan-Simon Pendry
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Jan-Simon Pendry.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * From:
38 * Id: procfs_vnops.c,v 4.2 1994/01/02 15:28:44 jsp Exp
39 *
40 * $Id: procfs_vnops.c,v 1.13 1994/01/20 21:23:10 ws Exp $
41 */
42
43 /*
44 * procfs vnode interface
45 */
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/time.h>
50 #include <sys/kernel.h>
51 #include <sys/file.h>
52 #include <sys/proc.h>
53 #include <sys/vnode.h>
54 #include <sys/namei.h>
55 #include <sys/malloc.h>
56 #include <sys/resourcevar.h>
57 #include <miscfs/procfs/procfs.h>
58 #include <vm/vm.h> /* for page_size */
59
60 #include <machine/reg.h>
61
62 /*
63 * Vnode Operations.
64 *
65 */
66
67 /*
68 * This is a list of the valid names in the
69 * process-specific sub-directories. It is
70 * used in procfs_lookup and procfs_readdir
71 */
72 static struct pfsnames {
73 u_short d_namlen;
74 char d_name[PROCFS_NAMELEN];
75 pfstype d_pfstype;
76 } procent[] = {
77 #define N(s) sizeof(s)-1, s
78 /* namlen, nam, type */
79 { N("."), Pproc },
80 { N(".."), Proot },
81 { N("file"), Pfile },
82 { N("mem"), Pmem },
83 { N("regs"), Pregs },
84 { N("ctl"), Pctl },
85 { N("status"), Pstatus },
86 { N("note"), Pnote },
87 { N("notepg"), Pnotepg },
88 #undef N
89 };
90 #define Nprocent (sizeof(procent)/sizeof(procent[0]))
91
92 #define PROCFS_XFILES 3 /* number of other entries, like "curproc" */
93
94 static pid_t atopid __P((const char *, u_int));
95
96 /*
97 * set things up for doing i/o on
98 * the pfsnode (vp). (vp) is locked
99 * on entry, and should be left locked
100 * on exit.
101 *
102 * for procfs we don't need to do anything
103 * in particular for i/o. all that is done
104 * is to support exclusive open on process
105 * memory images.
106 */
107 procfs_open(vp, mode, cred, p)
108 struct vnode *vp;
109 int mode;
110 struct ucred *cred;
111 struct proc *p;
112 {
113 struct pfsnode *pfs = VTOPFS(vp);
114
115 switch (pfs->pfs_type) {
116 case Pmem:
117 if (PFIND(pfs->pfs_pid) == 0)
118 return (ENOENT); /* was ESRCH, jsp */
119
120 if ((pfs->pfs_flags & FWRITE) && (mode & O_EXCL) ||
121 (pfs->pfs_flags & O_EXCL) && (mode & FWRITE))
122 return (EBUSY);
123
124
125 if (mode & FWRITE)
126 pfs->pfs_flags = (mode & (FWRITE|O_EXCL));
127
128 return (0);
129
130 default:
131 break;
132 }
133
134 return (0);
135 }
136
137 /*
138 * close the pfsnode (vp) after doing i/o.
139 * (vp) is not locked on entry or exit.
140 *
141 * nothing to do for procfs other than undo
142 * any exclusive open flag (see _open above).
143 */
144 procfs_close(vp, flag, cred, p)
145 struct vnode *vp;
146 int flag;
147 struct ucred *cred;
148 struct proc *p;
149 {
150 struct pfsnode *pfs = VTOPFS(vp);
151
152 switch (pfs->pfs_type) {
153 case Pmem:
154 if ((flag & FWRITE) && (pfs->pfs_flags & O_EXCL))
155 pfs->pfs_flags &= ~(FWRITE|O_EXCL);
156 break;
157 }
158
159 return (0);
160 }
161
162 /*
163 * do an ioctl operation on pfsnode (vp).
164 * (vp) is not locked on entry or exit.
165 */
166 procfs_ioctl(vp, com, data, fflag, cred, p)
167 struct vnode *vp;
168 int com;
169 caddr_t data;
170 int fflag;
171 struct ucred *cred;
172 struct proc *p;
173 {
174
175 return (ENOTTY);
176 }
177
178 /*
179 * do block mapping for pfsnode (vp).
180 * since we don't use the buffer cache
181 * for procfs this function should never
182 * be called. in any case, it's not clear
183 * what part of the kernel ever makes use
184 * of this function. for sanity, this is the
185 * usual no-op bmap, although returning
186 * (EIO) would be a reasonable alternative.
187 */
188 procfs_bmap(vp, bn, vpp, bnp)
189 struct vnode *vp;
190 daddr_t bn;
191 struct vnode **vpp;
192 daddr_t *bnp;
193 {
194
195 if (vpp != NULL)
196 *vpp = vp;
197 if (bnp != NULL)
198 *bnp = bn;
199 return (0);
200 }
201
202 /*
203 * _inactive is called when the pfsnode
204 * is vrele'd and the reference count goes
205 * to zero. (vp) will be on the vnode free
206 * list, so to get it back vget() must be
207 * used.
208 *
209 * for procfs, check if the process is still
210 * alive and if it isn't then just throw away
211 * the vnode by calling vgone(). this may
212 * be overkill and a waste of time since the
213 * chances are that the process will still be
214 * there and PFIND is not free.
215 *
216 * (vp) is not locked on entry or exit.
217 */
218 procfs_inactive(vp, p)
219 struct vnode *vp;
220 struct proc *p;
221 {
222 struct pfsnode *pfs = VTOPFS(vp);
223
224 if (PFIND(pfs->pfs_pid) == 0)
225 vgone(vp);
226
227 return (0);
228 }
229
230 /*
231 * _reclaim is called when getnewvnode()
232 * wants to make use of an entry on the vnode
233 * free list. at this time the filesystem needs
234 * to free any private data and remove the node
235 * from any private lists.
236 */
237 procfs_reclaim(vp)
238 struct vnode *vp;
239 {
240 int error;
241
242 error = procfs_freevp(vp);
243 return (error);
244 }
245
246 /*
247 * _print is used for debugging.
248 * just print a readable description
249 * of (vp).
250 */
251 procfs_print(vp)
252 struct vnode *vp;
253 {
254 struct pfsnode *pfs = VTOPFS(vp);
255
256 printf("tag VT_PROCFS, pid %d, mode %x, flags %x\n",
257 pfs->pfs_pid,
258 pfs->pfs_mode, pfs->pfs_flags);
259 }
260
261 /*
262 * _abortop is called when operations such as
263 * rename and create fail. this entry is responsible
264 * for undoing any side-effects caused by the lookup.
265 * this will always include freeing the pathname buffer.
266 */
267 procfs_abortop(ndp)
268 struct nameidata *ndp;
269 {
270
271 if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF)
272 FREE(ndp->ni_pnbuf, M_NAMEI);
273 return (0);
274 }
275
276 /*
277 * generic entry point for unsupported operations
278 */
279 procfs_badop()
280 {
281
282 return (EIO);
283 }
284
285 /*
286 * Invent attributes for pfsnode (vp) and store
287 * them in (vap).
288 * Directories lengths are returned as zero since
289 * any real length would require the genuine size
290 * to be computed, and nothing cares anyway.
291 *
292 * this is relatively minimal for procfs.
293 */
294 procfs_getattr(vp, vap, cred, p)
295 struct vnode *vp;
296 struct vattr *vap;
297 struct ucred *cred;
298 struct proc *p;
299 {
300 struct pfsnode *pfs = VTOPFS(vp);
301 struct proc *procp;
302 int error;
303
304 /* start by zeroing out the attributes */
305 VATTR_NULL(vap);
306
307 /* next do all the common fields */
308 vap->va_type = vp->v_type;
309 vap->va_mode = pfs->pfs_mode;
310 vap->va_fileid = pfs->pfs_fileno;
311 vap->va_flags = 0;
312 vap->va_blocksize = page_size;
313 vap->va_bytes = vap->va_size = 0;
314
315 /*
316 * Make all times be current TOD.
317 * It would be possible to get the process start
318 * time from the p_stat structure, but there's
319 * no "file creation" time stamp anyway, and the
320 * p_stat structure is not addressible if u. gets
321 * swapped out for that process.
322 */
323 microtime(&vap->va_ctime);
324 vap->va_atime = vap->va_mtime = vap->va_ctime;
325
326 error = 0;
327
328 if (pfs->pfs_type != Proot) {
329 /* check the process still exists */
330 procp = PFIND(pfs->pfs_pid);
331 if (procp == 0)
332 return (ENOENT);
333 /* most of the time we want these values */
334 vap->va_nlink = 1;
335 vap->va_uid = procp->p_ucred->cr_uid;
336 vap->va_gid = procp->p_ucred->cr_gid;
337 }
338
339 /*
340 * now do the object specific fields
341 *
342 * The size could be set from struct reg, but it's hardly
343 * worth the trouble, and it puts some (potentially) machine
344 * dependent data into this machine-independent code. If it
345 * becomes important then this function should break out into
346 * a per-file stat function in the corresponding .c file.
347 */
348
349 switch (pfs->pfs_type) {
350 case Proot:
351 switch ((int)pfs->pfs_pid) {
352 case 0: /* /proc */
353 vap->va_nlink = 2;
354 vap->va_uid = 0;
355 vap->va_gid = 0;
356 vap->va_bytes = vap->va_size
357 = (maxproc + 1 + PROCFS_XFILES) * UIO_MX;
358 break;
359 case 1: /* /proc/curproc */
360 vap->va_nlink = 1;
361 vap->va_uid = 0;
362 vap->va_gid = 0;
363 break;
364 default:
365 panic("procfs_getattr root");
366 }
367 break;
368
369 case Pproc:
370 vap->va_nlink = 2;
371 vap->va_bytes = vap->va_size = Nprocent * UIO_MX;
372 break;
373
374 case Pmem:
375 vap->va_bytes = vap->va_size =
376 ctob(procp->p_vmspace->vm_tsize +
377 procp->p_vmspace->vm_dsize +
378 procp->p_vmspace->vm_ssize);
379 break;
380
381 case Pregs:
382 vap->va_bytes = vap->va_size = sizeof(struct reg);
383 break;
384
385 case Pstatus:
386 vap->va_bytes = vap->va_size = 256; /* only a maximum */
387 break;
388
389 case Pctl:
390 vap->va_bytes = vap->va_size = PROCFS_CTLLEN;
391 break;
392
393 case Pnote:
394 vap->va_bytes = vap->va_size = PROCFS_NOTELEN;
395 break;
396
397 case Pnotepg:
398 break;
399
400 default:
401 panic("procfs_getattr type");
402 }
403
404 return (error);
405 }
406
407 procfs_setattr(vp, vap, cred, p)
408 struct vnode *vp;
409 struct vattr *vap;
410 struct ucred *cred;
411 struct proc *p;
412 {
413 /*
414 * just fake out attribute setting
415 * it's not good to generate an error
416 * return, otherwise things like creat()
417 * will fail when they try to set the
418 * file length to 0. worse, this means
419 * that echo $note > /proc/$pid/note will fail.
420 */
421
422 return (0);
423 }
424
425 /*
426 * implement access checking.
427 *
428 * something very similar to this code is duplicated
429 * throughout the 4bsd kernel and should be moved
430 * into kern/vfs_subr.c sometime.
431 *
432 * actually, the check for super-user is slightly
433 * broken since it will allow read access to write-only
434 * objects. this doesn't cause any particular trouble
435 * but does mean that the i/o entry points need to check
436 * that the operation really does make sense.
437 */
438 procfs_access(vp, mode, cred, p)
439 struct vnode *vp;
440 int mode;
441 struct ucred *cred;
442 struct proc *p;
443 {
444 struct vattr *vap;
445 struct vattr vattr;
446 int error;
447
448 /*
449 * If you're the super-user,
450 * you always get access.
451 */
452 if (cred->cr_uid == (uid_t) 0)
453 return (0);
454 vap = &vattr;
455 if (error = VOP_GETATTR(vp, vap, cred, p))
456 return (error);
457
458 /*
459 * Access check is based on only one of owner, group, public.
460 * If not owner, then check group. If not a member of the
461 * group, then check public access.
462 */
463 if (cred->cr_uid != vap->va_uid) {
464 gid_t *gp;
465 int i;
466
467 mode >>= 3;
468 gp = cred->cr_groups;
469 for (i = 0; i < cred->cr_ngroups; i++, gp++)
470 if (vap->va_gid == *gp)
471 goto found;
472 mode >>= 3;
473 found:
474 ;
475 }
476
477 if ((vap->va_mode & mode) == mode)
478 return (0);
479
480 return (EACCES);
481 }
482
483 /*
484 * lookup. this is incredibly complicated in the
485 * general case, however for most pseudo-filesystems
486 * very little needs to be done.
487 *
488 * (dvp) is the directory in which the lookup takes place.
489 * (ndp) contains all the information about the type of
490 * lookup being done.
491 *
492 * (dvp) is locked on entry.
493 * the job of lookup is to set ndp->ni_dvp, and ndp->ni_vp.
494 * (this changes in 4.4 where all we want is the equivalent
495 * of ndp->ni_vp.)
496 *
497 * unless you want to get a migraine, just make sure your
498 * filesystem doesn't do any locking of its own. otherwise
499 * read and inwardly digest ufs_lookup().
500 */
501 procfs_lookup(dvp, ndp, p)
502 struct vnode *dvp;
503 struct nameidata *ndp;
504 struct proc *p;
505 {
506 char *pname = ndp->ni_ptr;
507 int error = 0;
508 int flag;
509 pid_t pid;
510 struct vnode *nvp;
511 struct pfsnode *pfs;
512 struct proc *procp;
513 int mode;
514 pfstype pfs_type;
515 int i;
516
517 if (ndp->ni_namelen == 1 && *pname == '.') {
518 ndp->ni_vp = dvp;
519 ndp->ni_dvp = dvp;
520 VREF(dvp);
521 return (0);
522 }
523
524 ndp->ni_dvp = dvp;
525 ndp->ni_vp = NULL;
526
527 pfs = VTOPFS(dvp);
528 switch (pfs->pfs_type) {
529 case Proot:
530 if (ndp->ni_isdotdot)
531 return (EIO);
532
533 if (NDEQ(ndp, "curproc", 7)) {
534 if (error = procfs_allocvp(dvp->v_mount, &nvp, 1, Proot))
535 return error;
536 ndp->ni_vp = nvp;
537 return 0;
538 }
539
540 pid = atopid(pname, ndp->ni_namelen);
541 if (pid == NO_PID)
542 return (ENOENT);
543
544 procp = PFIND(pid);
545 if (procp == 0)
546 return (ENOENT);
547
548 error = procfs_allocvp(dvp->v_mount, &nvp, pid, Pproc);
549 if (error)
550 return (error);
551
552 ndp->ni_vp = nvp;
553 return (0);
554
555 case Pproc:
556 if (ndp->ni_isdotdot) {
557 ndp->ni_dvp = dvp;
558 error = procfs_root(dvp->v_mount, &ndp->ni_vp);
559 return (error);
560 }
561
562 procp = PFIND(pfs->pfs_pid);
563 if (procp == 0)
564 return (ENOENT);
565
566 for (i = 0; i < Nprocent; i++) {
567 struct pfsnames *dp = &procent[i];
568
569 if (ndp->ni_namelen == dp->d_namlen &&
570 bcmp(pname, dp->d_name, dp->d_namlen) == 0) {
571 pfs_type = dp->d_pfstype;
572 goto found;
573 }
574 }
575 return (ENOENT);
576
577 found:
578 if (pfs_type == Pfile) {
579 nvp = procfs_findtextvp(procp);
580 if (nvp) {
581 VREF(nvp);
582 VOP_LOCK(nvp);
583 } else {
584 error = ENXIO;
585 }
586 } else {
587 error = procfs_allocvp(dvp->v_mount, &nvp,
588 pfs->pfs_pid, pfs_type);
589 if (error)
590 return (error);
591
592 pfs = VTOPFS(nvp);
593 }
594 ndp->ni_vp = nvp;
595 return (error);
596
597 default:
598 return (ENOTDIR);
599 }
600 }
601
602 /*
603 * readdir returns directory entries from pfsnode (vp).
604 *
605 * the strategy here with procfs is to generate a single
606 * directory entry at a time (struct pfsdent) and then
607 * copy that out to userland using uiomove. a more efficent
608 * though more complex implementation, would try to minimize
609 * the number of calls to uiomove(). for procfs, this is
610 * hardly worth the added code complexity.
611 *
612 * this should just be done through read()
613 */
614 procfs_readdir(vp, uio, cred, eofflagp, cookies, ncookies)
615 struct vnode *vp;
616 struct uio *uio;
617 struct ucred *cred;
618 int *eofflagp;
619 u_int *cookies;
620 int ncookies;
621 {
622 struct pfsdent d;
623 struct pfsdent *dp = &d;
624 struct pfsnode *pfs;
625 int error;
626 int count;
627 int i;
628
629 /*
630 * NFS mounting of procfs doesn't work correctly.
631 * The files in procfs are more similar to devices
632 * than to regular files.
633 * See also procfs_vptofh & procfs_fhtovp in procfs_vfsops.c
634 */
635 if (cookies)
636 panic("procfs_readdir");
637
638 pfs = VTOPFS(vp);
639
640 if (uio->uio_resid < UIO_MX)
641 return (EINVAL);
642 if (uio->uio_offset & (UIO_MX-1))
643 return (EINVAL);
644 if (uio->uio_offset < 0)
645 return (EINVAL);
646
647 error = 0;
648 count = 0;
649 i = uio->uio_offset / UIO_MX;
650
651 switch (pfs->pfs_type) {
652 /*
653 * this is for the process-specific sub-directories.
654 * all that is needed to is copy out all the entries
655 * from the procent[] table (top of this file).
656 */
657 case Pproc: {
658 while (uio->uio_resid >= UIO_MX && (!cookies || ncookies > 0)) {
659 struct pfsnames *dt;
660 pid_t pid = pfs->pfs_pid;
661
662 if (i >= Nprocent) {
663 *eofflagp = 1;
664 break;
665 }
666
667 dt = &procent[i];
668 dp->d_reclen = UIO_MX;
669
670 if (dt->d_pfstype == Proot)
671 pid = 0;
672 dp->d_fileno = PROCFS_FILENO(pid, dt->d_pfstype);
673 dp->d_namlen = dt->d_namlen;
674 bcopy(dt->d_name, dp->d_name, sizeof(dt->d_name)-1);
675 error = uiomove((caddr_t) dp, UIO_MX, uio);
676 if (error)
677 break;
678 count += UIO_MX;
679 i++;
680 if (cookies) {
681 *cookies++ = i * UIO_MX;
682 ncookies--;
683 }
684 }
685
686 break;
687
688 }
689
690 /*
691 * this is for the root of the procfs filesystem
692 * what is needed is a special entry for "curproc"
693 * followed by an entry for each process on allproc
694 #ifdef PROCFS_ZOMBIE
695 * and zombproc.
696 #endif
697 */
698
699 case Proot: {
700 int pcnt;
701 #ifdef PROCFS_ZOMBIE
702 int doingzomb = 0;
703 #endif
704 struct proc *p;
705
706 p = (struct proc *) allproc;
707
708 pcnt = PROCFS_XFILES;
709
710 while (p && uio->uio_resid >= UIO_MX && (!cookies || ncookies > 0)) {
711 bzero((char *) dp, UIO_MX);
712 dp->d_reclen = UIO_MX;
713
714 switch (i) {
715 case 0: /* `.' */
716 case 1: /* `..' */
717 dp->d_fileno = PROCFS_FILENO(0, Proot);
718 bcopy("..",dp->d_name,3);
719 dp->d_namlen = i + 1;
720 dp->d_name[i + 1] = 0;
721 break;
722 case 2:
723 /* ship out entry for "curproc" */
724 dp->d_fileno = PROCFS_FILENO(1, Proot);
725 dp->d_namlen = 7;
726 bcopy("curproc", dp->d_name, dp->d_namlen+1);
727 break;
728
729 default:
730 if (pcnt >= i) {
731 dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc);
732 dp->d_namlen = sprintf(dp->d_name, "%ld", (long) p->p_pid);
733 }
734
735 p = p->p_nxt;
736
737 #ifdef PROCFS_ZOMBIE
738 if (p == 0 && doingzomb == 0) {
739 doingzomb = 1;
740 p = zombproc;
741 }
742 #endif
743
744 if (pcnt++ < i)
745 continue;
746
747 break;
748 }
749 error = uiomove((caddr_t) dp, UIO_MX, uio);
750 if (error)
751 break;
752 count += UIO_MX;
753 i++;
754 if (cookies) {
755 *cookies++ = i * UIO_MX;
756 ncookies--;
757 }
758 }
759
760 break;
761
762 }
763
764 default:
765 error = ENOTDIR;
766 break;
767 }
768
769 uio->uio_offset = i * UIO_MX;
770 if (count == 0)
771 *eofflagp = 1;
772
773 return (error);
774 }
775
776 /*
777 * readlink reads the link of "curproc"
778 */
779 procfs_readlink(vp, uio, cred)
780 struct vnode *vp;
781 struct uio *uio;
782 struct ucred *cred;
783 {
784 struct pfsnode *pfs = VTOPFS(vp);
785 char buf[16]; /* should be enough */
786 int len;
787
788 if (pfs->pfs_fileno != PROCFS_FILENO(1,Proot))
789 return EINVAL;
790
791 len = sprintf(buf,"%ld",(long)curproc->p_pid);
792
793 return uiomove(buf, len, uio);
794 }
795
796 /*
797 * convert decimal ascii to pid_t
798 */
799 static pid_t
800 atopid(b, len)
801 const char *b;
802 u_int len;
803 {
804 pid_t p = 0;
805
806 while (len--) {
807 char c = *b++;
808 if (c < '0' || c > '9')
809 return (NO_PID);
810 p = 10 * p + (c - '0');
811 if (p > PID_MAX)
812 return (NO_PID);
813 }
814
815 return (p);
816 }
817
818 /*
819 * procfs vnode operations.
820 */
821 struct vnodeops procfs_vnodeops = {
822 procfs_lookup, /* lookup */
823 procfs_create, /* create */
824 procfs_mknod, /* mknod */
825 procfs_open, /* open */
826 procfs_close, /* close */
827 procfs_access, /* access */
828 procfs_getattr, /* getattr */
829 procfs_setattr, /* setattr */
830 procfs_read, /* read */
831 procfs_write, /* write */
832 procfs_ioctl, /* ioctl */
833 procfs_select, /* select */
834 procfs_mmap, /* mmap */
835 procfs_fsync, /* fsync */
836 procfs_seek, /* seek */
837 procfs_remove, /* remove */
838 procfs_link, /* link */
839 procfs_rename, /* rename */
840 procfs_mkdir, /* mkdir */
841 procfs_rmdir, /* rmdir */
842 procfs_symlink, /* symlink */
843 procfs_readdir, /* readdir */
844 procfs_readlink, /* readlink */
845 procfs_abortop, /* abortop */
846 procfs_inactive, /* inactive */
847 procfs_reclaim, /* reclaim */
848 procfs_lock, /* lock */
849 procfs_unlock, /* unlock */
850 procfs_bmap, /* bmap */
851 procfs_strategy, /* strategy */
852 procfs_print, /* print */
853 procfs_islocked, /* islocked */
854 procfs_advlock, /* advlock */
855 };
856