kernfs_vnops.c revision 1.1 1 /*
2 * Copyright (c) 1992 The Regents of the University of California
3 * Copyright (c) 1990, 1992 Jan-Simon Pendry
4 * All rights reserved.
5 *
6 * This code is derived from software donated to Berkeley by
7 * Jan-Simon Pendry.
8 *
9 * %sccs.redist.c%
10 *
11 * %W% (Berkeley) %G%
12 *
13 * $Id: kernfs_vnops.c,v 1.1 1993/03/23 23:56:56 cgd Exp $
14 */
15
16 /*
17 * Kernel parameter filesystem
18 */
19
20 #include "param.h"
21 #include "systm.h"
22 #include "kernel.h"
23 #include "types.h"
24 #include "time.h"
25 #include "proc.h"
26 #include "file.h"
27 #include "vnode.h"
28 #include "stat.h"
29 #include "mount.h"
30 #include "namei.h"
31 #include "buf.h"
32 #include "miscfs/kernfs/kernfs.h"
33
34 #include "../ufs/dir.h" /* For readdir() XXX */
35
36 #define KSTRING 256 /* Largest I/O available via this filesystem */
37 #define UIO_MX 32
38
39 struct kern_target {
40 char *kt_name;
41 void *kt_data;
42 #define KTT_NULL 1
43 #define KTT_TIME 5
44 #define KTT_INT 17
45 #define KTT_STRING 31
46 #define KTT_HOSTNAME 47
47 #define KTT_AVENRUN 53
48 int kt_tag;
49 #define KTM_RO 0
50 #define KTM_RO_MODE (S_IRUSR|S_IRGRP|S_IROTH)
51 #define KTM_RW 43
52 #define KTM_RW_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)
53 #define KTM_DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
54 int kt_rw;
55 int kt_vtype;
56 } kern_targets[] = {
57 /* NOTE: The name must be less than UIO_MX-16 chars in length */
58 /* name data tag ro/rw */
59 { ".", 0, KTT_NULL, KTM_RO, VDIR },
60 { "copyright", copyright, KTT_STRING, KTM_RO, VREG },
61 { "hostname", 0, KTT_HOSTNAME, KTM_RW, VREG },
62 { "hz", &hz, KTT_INT, KTM_RO, VREG },
63 { "loadavg", 0, KTT_AVENRUN, KTM_RO, VREG },
64 { "physmem", &physmem, KTT_INT, KTM_RO, VREG },
65 { "root", 0, KTT_NULL, KTM_RO, VDIR },
66 { "rootdev", 0, KTT_NULL, KTM_RO, VBLK },
67 { "time", 0, KTT_TIME, KTM_RO, VREG },
68 { "version", version, KTT_STRING, KTM_RO, VREG },
69 };
70
71 static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]);
72
73 static int
74 kernfs_xread(kt, buf, len, lenp)
75 struct kern_target *kt;
76 char *buf;
77 int len;
78 int *lenp;
79 {
80 int xlen;
81
82 switch (kt->kt_tag) {
83 case KTT_TIME: {
84 struct timeval tv;
85 microtime(&tv);
86 sprintf(buf, "%d %d\n", tv.tv_sec, tv.tv_usec);
87 break;
88 }
89
90 case KTT_INT: {
91 int *ip = kt->kt_data;
92 sprintf(buf, "%d\n", *ip);
93 break;
94 }
95
96 case KTT_STRING: {
97 char *cp = kt->kt_data;
98 int xlen = strlen(cp) + 1;
99
100 if (xlen >= len)
101 return (EINVAL);
102
103 bcopy(cp, buf, xlen);
104 break;
105 }
106
107 case KTT_HOSTNAME: {
108 char *cp = hostname;
109 int xlen = hostnamelen;
110
111 if (xlen >= len)
112 return (EINVAL);
113
114 sprintf(buf, "%s\n", cp);
115 break;
116 }
117
118 case KTT_AVENRUN:
119 sprintf(buf, "%d %d %d %d\n",
120 averunnable[0],
121 averunnable[1],
122 averunnable[2],
123 FSCALE);
124 break;
125
126 default:
127 return (EINVAL);
128 }
129
130 *lenp = strlen(buf);
131 return (0);
132 }
133
134 static int
135 kernfs_xwrite(kt, buf, len)
136 struct kern_target *kt;
137 char *buf;
138 int len;
139 {
140 switch (kt->kt_tag) {
141 case KTT_HOSTNAME: {
142 if (buf[len-1] == '\n')
143 --len;
144 bcopy(buf, hostname, len);
145 hostnamelen = len - 1;
146 return (0);
147 }
148
149 default:
150 return (EIO);
151 }
152 }
153
154 /*
155 * vp is the current namei directory
156 * ndp is the name to locate in that directory...
157 */
158 kernfs_lookup(dvp, ndp, p)
159 struct vnode *dvp;
160 struct nameidata *ndp;
161 struct proc *p;
162 {
163 char *pname = ndp->ni_ptr;
164 int error = ENOENT;
165 int i;
166 struct vnode *fvp;
167
168 #ifdef KERNFS_DIAGNOSTIC
169 printf("kernfs_lookup(%s)\n", pname);
170 #endif
171 if (ndp->ni_namelen == 1 && *pname == '.') {
172 ndp->ni_dvp = dvp;
173 ndp->ni_vp = dvp;
174 VREF(dvp);
175 /*VOP_LOCK(dvp);*/
176 return (0);
177 }
178
179 if (ndp->ni_namelen == 4 && bcmp(pname, "root", 4) == 0) {
180 ndp->ni_dvp = rootdir;
181 ndp->ni_vp = rootdir;
182 VREF(rootdir);
183 VREF(rootdir);
184 VOP_LOCK(rootdir);
185 return (0);
186 }
187
188 /*
189 * /kern/rootdev is the root device
190 */
191 if (ndp->ni_namelen == 7 && bcmp(pname, "rootdev", 7) == 0) {
192 if (vfinddev(rootdev, VBLK, &fvp))
193 return (ENXIO);
194 ndp->ni_dvp = dvp;
195 ndp->ni_vp = fvp;
196 VREF(fvp);
197 VOP_LOCK(fvp);
198 return (0);
199 }
200
201 for (i = 0; i < nkern_targets; i++) {
202 struct kern_target *kt = &kern_targets[i];
203 if (ndp->ni_namelen == strlen(kt->kt_name) &&
204 bcmp(kt->kt_name, pname, ndp->ni_namelen) == 0) {
205 error = 0;
206 break;
207 }
208 }
209
210 #ifdef KERNFS_DIAGNOSTIC
211 printf("kernfs_lookup: i = %d, error = %d\n", i, error);
212 #endif
213
214 if (error)
215 goto bad;
216
217 #ifdef KERNFS_DIAGNOSTIC
218 printf("kernfs_lookup: allocate new vnode\n");
219 #endif
220 error = getnewvnode(VT_UFS, dvp->v_mount, &kernfs_vnodeops, &fvp);
221 if (error)
222 goto bad;
223 VTOKERN(fvp)->kf_kt = &kern_targets[i];
224 fvp->v_type = VTOKERN(fvp)->kf_kt->kt_vtype;
225 ndp->ni_dvp = dvp;
226 ndp->ni_vp = fvp;
227 #ifdef KERNFS_DIAGNOSTIC
228 printf("kernfs_lookup: newvp = %x\n", fvp);
229 #endif
230 return (0);
231
232 bad:;
233 ndp->ni_dvp = dvp;
234 ndp->ni_vp = NULL;
235 #ifdef KERNFS_DIAGNOSTIC
236 printf("kernfs_lookup: error = %d\n", error);
237 #endif
238 return (error);
239 }
240
241 kernfs_open(vp, mode, cred, p)
242 struct vnode *vp;
243 int mode;
244 struct ucred *cred;
245 struct proc *p;
246 {
247 int error;
248 struct filedesc *fdp;
249 struct file *fp;
250 int dfd;
251 int fd;
252
253 #ifdef KERNFS_DIAGNOSTIC
254 printf("kernfs_open\n");
255 #endif
256
257 /*
258 * Can always open the root (modulo perms)
259 */
260 if (vp->v_flag & VROOT)
261 return (0);
262
263 #ifdef KERNFS_DIAGNOSTIC
264 printf("kernfs_open, mode = %x, file = %s\n",
265 mode, VTOKERN(vp)->kf_kt->kt_name);
266 #endif
267
268 if ((mode & FWRITE) && VTOKERN(vp)->kf_kt->kt_rw != KTM_RW)
269 return (EBADF);
270
271 return (0);
272 }
273
274 kernfs_getattr(vp, vap, cred, p)
275 struct vnode *vp;
276 struct vattr *vap;
277 struct ucred *cred;
278 struct proc *p;
279 {
280 int error = 0;
281 char strbuf[KSTRING];
282 struct kern_target *kt = VTOKERN(vp)->kf_kt;
283
284 bzero((caddr_t) vap, sizeof(*vap));
285 vattr_null(vap);
286 vap->va_uid = 0;
287 vap->va_gid = 0;
288 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
289 /* vap->va_qsize = 0; */
290 vap->va_blocksize = DEV_BSIZE;
291 microtime(&vap->va_atime);
292 vap->va_mtime = vap->va_atime;
293 vap->va_ctime = vap->va_ctime;
294 vap->va_gen = 0;
295 vap->va_flags = 0;
296 vap->va_rdev = 0;
297 /* vap->va_qbytes = 0; */
298 vap->va_bytes = 0;
299
300 if (vp->v_flag & VROOT) {
301 #ifdef KERNFS_DIAGNOSTIC
302 printf("kernfs_getattr: stat rootdir\n");
303 #endif
304 vap->va_type = VDIR;
305 vap->va_mode = KTM_DIR_MODE;
306 vap->va_nlink = 2;
307 vap->va_fileid = 2;
308 vap->va_size = DEV_BSIZE;
309 } else {
310 #ifdef KERNFS_DIAGNOSTIC
311 printf("kernfs_getattr: stat target %s\n", kt->kt_name);
312 #endif
313 vap->va_type = kt->kt_vtype;
314 vap->va_mode = (kt->kt_rw ? KTM_RW_MODE : KTM_RO_MODE);
315 vap->va_nlink = 1;
316 vap->va_fileid = 3 + (kt - kern_targets) / sizeof(*kt);
317 error = kernfs_xread(kt, strbuf, sizeof(strbuf), &vap->va_size);
318 }
319
320 vp->v_type = vap->va_type;
321 #ifdef KERNFS_DIAGNOSTIC
322 printf("kernfs_getattr: return error %d\n", error);
323 #endif
324 return (error);
325 }
326
327 kernfs_setattr(vp, vap, cred, p)
328 struct vnode *vp;
329 struct vattr *vap;
330 struct ucred *cred;
331 struct proc *p;
332 {
333
334 /*
335 * Silently ignore attribute changes.
336 * This allows for open with truncate to have no
337 * effect until some data is written. I want to
338 * do it this way because all writes are atomic.
339 */
340 return (0);
341 }
342
343 static int
344 kernfs_read(vp, uio, ioflag, cred)
345 struct vnode *vp;
346 struct uio *uio;
347 int ioflag;
348 struct ucred *cred;
349 {
350 struct kern_target *kt = VTOKERN(vp)->kf_kt;
351 char strbuf[KSTRING];
352 int off = uio->uio_offset;
353 int len = 0;
354 char *cp = strbuf;
355 int error;
356 #ifdef KERNFS_DIAGNOSTIC
357 printf("kern_read %s\n", kt->kt_name);
358 #endif
359
360 error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len);
361 if (error)
362 return (error);
363 cp = strbuf + off;
364 len -= off;
365 return (uiomove(cp, len, uio));
366 }
367
368 static int
369 kernfs_write(vp, uio, ioflag, cred)
370 struct vnode *vp;
371 struct uio *uio;
372 int ioflag;
373 struct ucred *cred;
374 {
375 struct kern_target *kt = VTOKERN(vp)->kf_kt;
376 char strbuf[KSTRING];
377 int len = uio->uio_resid;
378 char *cp = strbuf;
379 int xlen;
380 int error;
381
382 if (uio->uio_offset != 0)
383 return (EINVAL);
384
385 xlen = min(uio->uio_resid, KSTRING-1);
386 error = uiomove(strbuf, xlen, uio);
387 if (error)
388 return (error);
389
390 if (uio->uio_resid != 0)
391 return (EIO);
392
393 strbuf[xlen] = '\0';
394 return (kernfs_xwrite(kt, strbuf, xlen));
395 }
396
397 kernfs_readdir(vp, uio, cred, eofflagp)
398 struct vnode *vp;
399 struct uio *uio;
400 struct ucred *cred;
401 int *eofflagp;
402 {
403 struct filedesc *fdp;
404 int i;
405 int error;
406
407 i = uio->uio_offset / UIO_MX;
408 error = 0;
409 while (uio->uio_resid > 0) {
410 #ifdef KERNFS_DIAGNOSTIC
411 printf("kernfs_readdir: i = %d\n", i);
412 #endif
413 if (i >= nkern_targets) {
414 *eofflagp = 1;
415 break;
416 }
417 {
418 struct direct d;
419 struct direct *dp = &d;
420 struct kern_target *kt = &kern_targets[i];
421
422 bzero((caddr_t) dp, UIO_MX);
423
424 dp->d_namlen = strlen(kt->kt_name);
425 bcopy(kt->kt_name, dp->d_name, dp->d_namlen+1);
426
427 #ifdef KERNFS_DIAGNOSTIC
428 printf("kernfs_readdir: name = %s, len = %d\n",
429 dp->d_name, dp->d_namlen);
430 #endif
431 /*
432 * Fill in the remaining fields
433 */
434 dp->d_reclen = UIO_MX;
435 dp->d_ino = i + 3;
436 /*
437 * And ship to userland
438 */
439 error = uiomove((caddr_t) dp, UIO_MX, uio);
440 if (error)
441 break;
442 }
443 i++;
444 }
445
446 uio->uio_offset = i * UIO_MX;
447
448 return (error);
449 }
450
451 kernfs_inactive(vp, p)
452 struct vnode *vp;
453 struct proc *p;
454 {
455 /*
456 * Clear out the v_type field to avoid
457 * nasty things happening in vgone().
458 */
459 vp->v_type = VNON;
460 #ifdef KERNFS_DIAGNOSTIC
461 printf("kernfs_inactive(%x)\n", vp);
462 #endif
463 return (0);
464 }
465
466 /*
467 * Print out the contents of a kernfs vnode.
468 */
469 /* ARGSUSED */
470 kernfs_print(vp)
471 struct vnode *vp;
472 {
473 printf("tag VT_NON, kernfs vnode\n");
474 }
475
476 /*
477 * kernfs vnode unsupported operation
478 */
479 kernfs_enotsupp()
480 {
481 return (EOPNOTSUPP);
482 }
483
484 /*
485 * kernfs "should never get here" operation
486 */
487 kernfs_badop()
488 {
489 panic("kernfs: bad op");
490 /* NOTREACHED */
491 }
492
493 /*
494 * kernfs vnode null operation
495 */
496 kernfs_nullop()
497 {
498 return (0);
499 }
500
501 #define kernfs_create ((int (*) __P(( \
502 struct nameidata *ndp, \
503 struct vattr *vap, \
504 struct proc *p))) kernfs_enotsupp)
505 #define kernfs_mknod ((int (*) __P(( \
506 struct nameidata *ndp, \
507 struct vattr *vap, \
508 struct ucred *cred, \
509 struct proc *p))) kernfs_enotsupp)
510 #define kernfs_close ((int (*) __P(( \
511 struct vnode *vp, \
512 int fflag, \
513 struct ucred *cred, \
514 struct proc *p))) nullop)
515 #define kernfs_access ((int (*) __P(( \
516 struct vnode *vp, \
517 int mode, \
518 struct ucred *cred, \
519 struct proc *p))) nullop)
520 #define kernfs_ioctl ((int (*) __P(( \
521 struct vnode *vp, \
522 int command, \
523 caddr_t data, \
524 int fflag, \
525 struct ucred *cred, \
526 struct proc *p))) kernfs_enotsupp)
527 #define kernfs_select ((int (*) __P(( \
528 struct vnode *vp, \
529 int which, \
530 int fflags, \
531 struct ucred *cred, \
532 struct proc *p))) kernfs_enotsupp)
533 #define kernfs_mmap ((int (*) __P(( \
534 struct vnode *vp, \
535 int fflags, \
536 struct ucred *cred, \
537 struct proc *p))) kernfs_enotsupp)
538 #define kernfs_fsync ((int (*) __P(( \
539 struct vnode *vp, \
540 int fflags, \
541 struct ucred *cred, \
542 int waitfor, \
543 struct proc *p))) nullop)
544 #define kernfs_seek ((int (*) __P(( \
545 struct vnode *vp, \
546 off_t oldoff, \
547 off_t newoff, \
548 struct ucred *cred))) nullop)
549 #define kernfs_remove ((int (*) __P(( \
550 struct nameidata *ndp, \
551 struct proc *p))) kernfs_enotsupp)
552 #define kernfs_link ((int (*) __P(( \
553 struct vnode *vp, \
554 struct nameidata *ndp, \
555 struct proc *p))) kernfs_enotsupp)
556 #define kernfs_rename ((int (*) __P(( \
557 struct nameidata *fndp, \
558 struct nameidata *tdnp, \
559 struct proc *p))) kernfs_enotsupp)
560 #define kernfs_mkdir ((int (*) __P(( \
561 struct nameidata *ndp, \
562 struct vattr *vap, \
563 struct proc *p))) kernfs_enotsupp)
564 #define kernfs_rmdir ((int (*) __P(( \
565 struct nameidata *ndp, \
566 struct proc *p))) kernfs_enotsupp)
567 #define kernfs_symlink ((int (*) __P(( \
568 struct nameidata *ndp, \
569 struct vattr *vap, \
570 char *target, \
571 struct proc *p))) kernfs_enotsupp)
572 #define kernfs_readlink ((int (*) __P(( \
573 struct vnode *vp, \
574 struct uio *uio, \
575 struct ucred *cred))) kernfs_enotsupp)
576 #define kernfs_abortop ((int (*) __P(( \
577 struct nameidata *ndp))) nullop)
578 #ifdef KERNFS_DIAGNOSTIC
579 int kernfs_reclaim(vp)
580 struct vnode *vp;
581 {
582 printf("kernfs_reclaim(%x)\n", vp);
583 return (0);
584 }
585 #else
586 #define kernfs_reclaim ((int (*) __P(( \
587 struct vnode *vp))) nullop)
588 #endif
589 #define kernfs_lock ((int (*) __P(( \
590 struct vnode *vp))) nullop)
591 #define kernfs_unlock ((int (*) __P(( \
592 struct vnode *vp))) nullop)
593 #define kernfs_bmap ((int (*) __P(( \
594 struct vnode *vp, \
595 daddr_t bn, \
596 struct vnode **vpp, \
597 daddr_t *bnp))) kernfs_badop)
598 #define kernfs_strategy ((int (*) __P(( \
599 struct buf *bp))) kernfs_badop)
600 #define kernfs_islocked ((int (*) __P(( \
601 struct vnode *vp))) nullop)
602 #define kernfs_advlock ((int (*) __P(( \
603 struct vnode *vp, \
604 caddr_t id, \
605 int op, \
606 struct flock *fl, \
607 int flags))) kernfs_enotsupp)
608
609 struct vnodeops kernfs_vnodeops = {
610 kernfs_lookup, /* lookup */
611 kernfs_create, /* create */
612 kernfs_mknod, /* mknod */
613 kernfs_open, /* open */
614 kernfs_close, /* close */
615 kernfs_access, /* access */
616 kernfs_getattr, /* getattr */
617 kernfs_setattr, /* setattr */
618 kernfs_read, /* read */
619 kernfs_write, /* write */
620 kernfs_ioctl, /* ioctl */
621 kernfs_select, /* select */
622 kernfs_mmap, /* mmap */
623 kernfs_fsync, /* fsync */
624 kernfs_seek, /* seek */
625 kernfs_remove, /* remove */
626 kernfs_link, /* link */
627 kernfs_rename, /* rename */
628 kernfs_mkdir, /* mkdir */
629 kernfs_rmdir, /* rmdir */
630 kernfs_symlink, /* symlink */
631 kernfs_readdir, /* readdir */
632 kernfs_readlink, /* readlink */
633 kernfs_abortop, /* abortop */
634 kernfs_inactive, /* inactive */
635 kernfs_reclaim, /* reclaim */
636 kernfs_lock, /* lock */
637 kernfs_unlock, /* unlock */
638 kernfs_bmap, /* bmap */
639 kernfs_strategy, /* strategy */
640 kernfs_print, /* print */
641 kernfs_islocked, /* islocked */
642 kernfs_advlock, /* advlock */
643 };
644