Commit | Line | Data |
---|---|---|
a1d35437 | 1 | /* |
1446b03c KB |
2 | * Copyright (c) 1989, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
a1d35437 | 4 | * |
dbf0c423 | 5 | * %sccs.include.redist.c% |
a1d35437 | 6 | * |
dd66b105 | 7 | * @(#)spec_vnops.c 8.10 (Berkeley) %G% |
a1d35437 KM |
8 | */ |
9 | ||
17c64659 KB |
10 | #include <sys/param.h> |
11 | #include <sys/proc.h> | |
12 | #include <sys/systm.h> | |
13 | #include <sys/kernel.h> | |
14 | #include <sys/conf.h> | |
15 | #include <sys/buf.h> | |
16 | #include <sys/mount.h> | |
17 | #include <sys/namei.h> | |
18 | #include <sys/vnode.h> | |
17c64659 KB |
19 | #include <sys/stat.h> |
20 | #include <sys/errno.h> | |
21 | #include <sys/ioctl.h> | |
22 | #include <sys/file.h> | |
23 | #include <sys/disklabel.h> | |
a798c07b | 24 | #include <miscfs/specfs/specdev.h> |
a1d35437 | 25 | |
ccee3c59 MK |
26 | /* symbolic sleep message strings for devices */ |
27 | char devopn[] = "devopn"; | |
28 | char devio[] = "devio"; | |
29 | char devwait[] = "devwait"; | |
30 | char devin[] = "devin"; | |
31 | char devout[] = "devout"; | |
32 | char devioc[] = "devioc"; | |
33 | char devcls[] = "devcls"; | |
34 | ||
9342689a JH |
35 | int (**spec_vnodeop_p)(); |
36 | struct vnodeopv_entry_desc spec_vnodeop_entries[] = { | |
37 | { &vop_default_desc, vn_default_error }, | |
38 | { &vop_lookup_desc, spec_lookup }, /* lookup */ | |
39 | { &vop_create_desc, spec_create }, /* create */ | |
40 | { &vop_mknod_desc, spec_mknod }, /* mknod */ | |
b7c4b3cc | 41 | { &vop_open_desc, spec_open }, /* open */ |
9342689a JH |
42 | { &vop_close_desc, spec_close }, /* close */ |
43 | { &vop_access_desc, spec_access }, /* access */ | |
44 | { &vop_getattr_desc, spec_getattr }, /* getattr */ | |
45 | { &vop_setattr_desc, spec_setattr }, /* setattr */ | |
b7c4b3cc | 46 | { &vop_read_desc, spec_read }, /* read */ |
9342689a | 47 | { &vop_write_desc, spec_write }, /* write */ |
12c92474 | 48 | { &vop_lease_desc, spec_lease_check }, /* lease */ |
9342689a JH |
49 | { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ |
50 | { &vop_select_desc, spec_select }, /* select */ | |
b7c4b3cc | 51 | { &vop_mmap_desc, spec_mmap }, /* mmap */ |
9342689a | 52 | { &vop_fsync_desc, spec_fsync }, /* fsync */ |
b7c4b3cc | 53 | { &vop_seek_desc, spec_seek }, /* seek */ |
9342689a | 54 | { &vop_remove_desc, spec_remove }, /* remove */ |
b7c4b3cc | 55 | { &vop_link_desc, spec_link }, /* link */ |
9342689a JH |
56 | { &vop_rename_desc, spec_rename }, /* rename */ |
57 | { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ | |
58 | { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ | |
59 | { &vop_symlink_desc, spec_symlink }, /* symlink */ | |
60 | { &vop_readdir_desc, spec_readdir }, /* readdir */ | |
61 | { &vop_readlink_desc, spec_readlink }, /* readlink */ | |
62 | { &vop_abortop_desc, spec_abortop }, /* abortop */ | |
63 | { &vop_inactive_desc, spec_inactive }, /* inactive */ | |
64 | { &vop_reclaim_desc, spec_reclaim }, /* reclaim */ | |
b7c4b3cc | 65 | { &vop_lock_desc, spec_lock }, /* lock */ |
9342689a | 66 | { &vop_unlock_desc, spec_unlock }, /* unlock */ |
b7c4b3cc | 67 | { &vop_bmap_desc, spec_bmap }, /* bmap */ |
9342689a JH |
68 | { &vop_strategy_desc, spec_strategy }, /* strategy */ |
69 | { &vop_print_desc, spec_print }, /* print */ | |
70 | { &vop_islocked_desc, spec_islocked }, /* islocked */ | |
b7c4b3cc | 71 | { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ |
9342689a JH |
72 | { &vop_advlock_desc, spec_advlock }, /* advlock */ |
73 | { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ | |
9342689a JH |
74 | { &vop_valloc_desc, spec_valloc }, /* valloc */ |
75 | { &vop_vfree_desc, spec_vfree }, /* vfree */ | |
76 | { &vop_truncate_desc, spec_truncate }, /* truncate */ | |
77 | { &vop_update_desc, spec_update }, /* update */ | |
78 | { &vop_bwrite_desc, spec_bwrite }, /* bwrite */ | |
79 | { (struct vnodeop_desc*)NULL, (int(*)())NULL } | |
a1d35437 | 80 | }; |
9342689a JH |
81 | struct vnodeopv_desc spec_vnodeop_opv_desc = |
82 | { &spec_vnodeop_p, spec_vnodeop_entries }; | |
a1d35437 | 83 | |
59b0713e KM |
84 | /* |
85 | * Trivial lookup routine that always fails. | |
86 | */ | |
6ee99c46 | 87 | int |
e2afbd7b KM |
88 | spec_lookup(ap) |
89 | struct vop_lookup_args /* { | |
90 | struct vnode *a_dvp; | |
91 | struct vnode **a_vpp; | |
92 | struct componentname *a_cnp; | |
93 | } */ *ap; | |
59b0713e KM |
94 | { |
95 | ||
e1b76915 | 96 | *ap->a_vpp = NULL; |
59b0713e KM |
97 | return (ENOTDIR); |
98 | } | |
99 | ||
a1d35437 | 100 | /* |
196b7053 | 101 | * Open a special file. |
a1d35437 | 102 | */ |
3d5d83ff | 103 | /* ARGSUSED */ |
e2afbd7b KM |
104 | spec_open(ap) |
105 | struct vop_open_args /* { | |
106 | struct vnode *a_vp; | |
107 | int a_mode; | |
108 | struct ucred *a_cred; | |
109 | struct proc *a_p; | |
110 | } */ *ap; | |
a1d35437 | 111 | { |
196b7053 KM |
112 | struct vnode *bvp, *vp = ap->a_vp; |
113 | dev_t bdev, dev = (dev_t)vp->v_rdev; | |
a1d35437 | 114 | register int maj = major(dev); |
5b2e9327 | 115 | int error; |
a1d35437 | 116 | |
196b7053 KM |
117 | /* |
118 | * Don't allow open if fs is mounted -nodev. | |
119 | */ | |
406c9a0d | 120 | if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) |
786053cd KM |
121 | return (ENXIO); |
122 | ||
406c9a0d | 123 | switch (vp->v_type) { |
a1d35437 KM |
124 | |
125 | case VCHR: | |
126 | if ((u_int)maj >= nchrdev) | |
127 | return (ENXIO); | |
196b7053 KM |
128 | if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) { |
129 | /* | |
130 | * When running in very secure mode, do not allow | |
131 | * opens for writing of any disk character devices. | |
132 | */ | |
5757dc03 | 133 | if (securelevel >= 2 && cdevsw[maj].d_type == D_DISK) |
196b7053 KM |
134 | return (EPERM); |
135 | /* | |
136 | * When running in secure mode, do not allow opens | |
137 | * for writing of /dev/mem, /dev/kmem, or character | |
138 | * devices whose corresponding block devices are | |
139 | * currently mounted. | |
140 | */ | |
141 | if (securelevel >= 1) { | |
142 | if ((bdev = chrtoblk(dev)) != NODEV && | |
143 | vfinddev(bdev, VBLK, &bvp) && | |
144 | bvp->v_usecount > 0 && | |
21c31ae2 | 145 | (error = vfs_mountedon(bvp))) |
196b7053 KM |
146 | return (error); |
147 | if (iskmemdev(dev)) | |
148 | return (EPERM); | |
149 | } | |
150 | } | |
5757dc03 | 151 | if (cdevsw[maj].d_type == D_TTY) |
f945a24f | 152 | vp->v_flag |= VISTTY; |
406c9a0d | 153 | VOP_UNLOCK(vp); |
e1b76915 | 154 | error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p); |
406c9a0d | 155 | VOP_LOCK(vp); |
b3bf09c7 | 156 | return (error); |
a1d35437 KM |
157 | |
158 | case VBLK: | |
159 | if ((u_int)maj >= nblkdev) | |
160 | return (ENXIO); | |
196b7053 KM |
161 | /* |
162 | * When running in very secure mode, do not allow | |
163 | * opens for writing of any disk block devices. | |
164 | */ | |
165 | if (securelevel >= 2 && ap->a_cred != FSCRED && | |
5757dc03 | 166 | (ap->a_mode & FWRITE) && bdevsw[maj].d_type == D_DISK) |
196b7053 KM |
167 | return (EPERM); |
168 | /* | |
169 | * Do not allow opens of block devices that are | |
170 | * currently mounted. | |
171 | */ | |
21c31ae2 | 172 | if (error = vfs_mountedon(vp)) |
5b2e9327 | 173 | return (error); |
e1b76915 | 174 | return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p)); |
a1d35437 KM |
175 | } |
176 | return (0); | |
177 | } | |
178 | ||
a1d35437 KM |
179 | /* |
180 | * Vnode op for read | |
181 | */ | |
fe6cdffe | 182 | /* ARGSUSED */ |
e2afbd7b KM |
183 | spec_read(ap) |
184 | struct vop_read_args /* { | |
185 | struct vnode *a_vp; | |
186 | struct uio *a_uio; | |
187 | int a_ioflag; | |
188 | struct ucred *a_cred; | |
189 | } */ *ap; | |
a1d35437 | 190 | { |
406c9a0d JH |
191 | register struct vnode *vp = ap->a_vp; |
192 | register struct uio *uio = ap->a_uio; | |
193 | struct proc *p = uio->uio_procp; | |
7d4e5ac1 | 194 | struct buf *bp; |
2e4bbf7a | 195 | daddr_t bn, nextbn; |
7d4e5ac1 KM |
196 | long bsize, bscale; |
197 | struct partinfo dpart; | |
714d32cb | 198 | int n, on, majordev, (*ioctl)(); |
7d4e5ac1 | 199 | int error = 0; |
714d32cb | 200 | dev_t dev; |
a1d35437 | 201 | |
68a834b0 | 202 | #ifdef DIAGNOSTIC |
406c9a0d | 203 | if (uio->uio_rw != UIO_READ) |
43444338 | 204 | panic("spec_read mode"); |
406c9a0d | 205 | if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) |
68a834b0 KM |
206 | panic("spec_read proc"); |
207 | #endif | |
406c9a0d | 208 | if (uio->uio_resid == 0) |
43444338 | 209 | return (0); |
43444338 | 210 | |
406c9a0d | 211 | switch (vp->v_type) { |
43444338 KM |
212 | |
213 | case VCHR: | |
406c9a0d JH |
214 | VOP_UNLOCK(vp); |
215 | error = (*cdevsw[major(vp->v_rdev)].d_read) | |
216 | (vp->v_rdev, uio, ap->a_ioflag); | |
217 | VOP_LOCK(vp); | |
43444338 KM |
218 | return (error); |
219 | ||
220 | case VBLK: | |
406c9a0d | 221 | if (uio->uio_offset < 0) |
43444338 | 222 | return (EINVAL); |
7d4e5ac1 | 223 | bsize = BLKDEV_IOSIZE; |
714d32cb KM |
224 | dev = vp->v_rdev; |
225 | if ((majordev = major(dev)) < nblkdev && | |
226 | (ioctl = bdevsw[majordev].d_ioctl) != NULL && | |
227 | (*ioctl)(dev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0 && | |
228 | dpart.part->p_fstype == FS_BSDFFS && | |
229 | dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) | |
230 | bsize = dpart.part->p_frag * dpart.part->p_fsize; | |
7d4e5ac1 KM |
231 | bscale = bsize / DEV_BSIZE; |
232 | do { | |
406c9a0d JH |
233 | bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1); |
234 | on = uio->uio_offset % bsize; | |
48c77711 | 235 | n = min((unsigned)(bsize - on), uio->uio_resid); |
406c9a0d | 236 | if (vp->v_lastr + bscale == bn) { |
2e4bbf7a | 237 | nextbn = bn + bscale; |
406c9a0d | 238 | error = breadn(vp, bn, (int)bsize, &nextbn, |
2e4bbf7a KM |
239 | (int *)&bsize, 1, NOCRED, &bp); |
240 | } else | |
406c9a0d JH |
241 | error = bread(vp, bn, (int)bsize, NOCRED, &bp); |
242 | vp->v_lastr = bn; | |
48c77711 | 243 | n = min(n, bsize - bp->b_resid); |
7d4e5ac1 KM |
244 | if (error) { |
245 | brelse(bp); | |
246 | return (error); | |
247 | } | |
6e36b147 | 248 | error = uiomove((char *)bp->b_data + on, n, uio); |
7d4e5ac1 KM |
249 | if (n + on == bsize) |
250 | bp->b_flags |= B_AGE; | |
251 | brelse(bp); | |
406c9a0d | 252 | } while (error == 0 && uio->uio_resid > 0 && n != 0); |
7d4e5ac1 | 253 | return (error); |
43444338 KM |
254 | |
255 | default: | |
256 | panic("spec_read type"); | |
257 | } | |
258 | /* NOTREACHED */ | |
a1d35437 KM |
259 | } |
260 | ||
261 | /* | |
262 | * Vnode op for write | |
263 | */ | |
fe6cdffe | 264 | /* ARGSUSED */ |
e2afbd7b KM |
265 | spec_write(ap) |
266 | struct vop_write_args /* { | |
267 | struct vnode *a_vp; | |
268 | struct uio *a_uio; | |
269 | int a_ioflag; | |
270 | struct ucred *a_cred; | |
271 | } */ *ap; | |
a1d35437 | 272 | { |
406c9a0d JH |
273 | register struct vnode *vp = ap->a_vp; |
274 | register struct uio *uio = ap->a_uio; | |
275 | struct proc *p = uio->uio_procp; | |
7d4e5ac1 KM |
276 | struct buf *bp; |
277 | daddr_t bn; | |
278 | int bsize, blkmask; | |
279 | struct partinfo dpart; | |
9db58063 KM |
280 | register int n, on; |
281 | int error = 0; | |
a1d35437 | 282 | |
68a834b0 | 283 | #ifdef DIAGNOSTIC |
406c9a0d | 284 | if (uio->uio_rw != UIO_WRITE) |
43444338 | 285 | panic("spec_write mode"); |
406c9a0d | 286 | if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) |
68a834b0 KM |
287 | panic("spec_write proc"); |
288 | #endif | |
43444338 | 289 | |
406c9a0d | 290 | switch (vp->v_type) { |
43444338 KM |
291 | |
292 | case VCHR: | |
406c9a0d JH |
293 | VOP_UNLOCK(vp); |
294 | error = (*cdevsw[major(vp->v_rdev)].d_write) | |
295 | (vp->v_rdev, uio, ap->a_ioflag); | |
296 | VOP_LOCK(vp); | |
43444338 KM |
297 | return (error); |
298 | ||
299 | case VBLK: | |
406c9a0d | 300 | if (uio->uio_resid == 0) |
43444338 | 301 | return (0); |
406c9a0d | 302 | if (uio->uio_offset < 0) |
43444338 | 303 | return (EINVAL); |
7d4e5ac1 | 304 | bsize = BLKDEV_IOSIZE; |
406c9a0d | 305 | if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART, |
8429d022 | 306 | (caddr_t)&dpart, FREAD, p) == 0) { |
7d4e5ac1 KM |
307 | if (dpart.part->p_fstype == FS_BSDFFS && |
308 | dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) | |
309 | bsize = dpart.part->p_frag * | |
310 | dpart.part->p_fsize; | |
311 | } | |
312 | blkmask = (bsize / DEV_BSIZE) - 1; | |
313 | do { | |
406c9a0d JH |
314 | bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask; |
315 | on = uio->uio_offset % bsize; | |
48c77711 | 316 | n = min((unsigned)(bsize - on), uio->uio_resid); |
7d4e5ac1 | 317 | if (n == bsize) |
c74a8e8b | 318 | bp = getblk(vp, bn, bsize, 0, 0); |
7d4e5ac1 | 319 | else |
406c9a0d | 320 | error = bread(vp, bn, bsize, NOCRED, &bp); |
48c77711 | 321 | n = min(n, bsize - bp->b_resid); |
7d4e5ac1 KM |
322 | if (error) { |
323 | brelse(bp); | |
324 | return (error); | |
325 | } | |
6e36b147 | 326 | error = uiomove((char *)bp->b_data + on, n, uio); |
7d4e5ac1 KM |
327 | if (n + on == bsize) { |
328 | bp->b_flags |= B_AGE; | |
329 | bawrite(bp); | |
330 | } else | |
331 | bdwrite(bp); | |
406c9a0d | 332 | } while (error == 0 && uio->uio_resid > 0 && n != 0); |
7d4e5ac1 | 333 | return (error); |
43444338 KM |
334 | |
335 | default: | |
336 | panic("spec_write type"); | |
337 | } | |
338 | /* NOTREACHED */ | |
a1d35437 KM |
339 | } |
340 | ||
341 | /* | |
342 | * Device ioctl operation. | |
343 | */ | |
3d5d83ff | 344 | /* ARGSUSED */ |
e2afbd7b KM |
345 | spec_ioctl(ap) |
346 | struct vop_ioctl_args /* { | |
347 | struct vnode *a_vp; | |
348 | int a_command; | |
349 | caddr_t a_data; | |
350 | int a_fflag; | |
351 | struct ucred *a_cred; | |
352 | struct proc *a_p; | |
353 | } */ *ap; | |
a1d35437 | 354 | { |
e1b76915 | 355 | dev_t dev = ap->a_vp->v_rdev; |
a1d35437 | 356 | |
e1b76915 | 357 | switch (ap->a_vp->v_type) { |
a1d35437 KM |
358 | |
359 | case VCHR: | |
e1b76915 JH |
360 | return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, |
361 | ap->a_fflag, ap->a_p)); | |
a1d35437 KM |
362 | |
363 | case VBLK: | |
e1b76915 | 364 | if (ap->a_command == 0 && (int)ap->a_data == B_TAPE) |
5757dc03 | 365 | if (bdevsw[major(dev)].d_type == D_TAPE) |
b9a4d0ff KM |
366 | return (0); |
367 | else | |
368 | return (1); | |
e1b76915 JH |
369 | return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, |
370 | ap->a_fflag, ap->a_p)); | |
a1d35437 KM |
371 | |
372 | default: | |
ad27f720 | 373 | panic("spec_ioctl"); |
a1d35437 KM |
374 | /* NOTREACHED */ |
375 | } | |
376 | } | |
377 | ||
3d5d83ff | 378 | /* ARGSUSED */ |
e2afbd7b KM |
379 | spec_select(ap) |
380 | struct vop_select_args /* { | |
381 | struct vnode *a_vp; | |
382 | int a_which; | |
383 | int a_fflags; | |
384 | struct ucred *a_cred; | |
385 | struct proc *a_p; | |
386 | } */ *ap; | |
a1d35437 | 387 | { |
a1d35437 KM |
388 | register dev_t dev; |
389 | ||
e1b76915 | 390 | switch (ap->a_vp->v_type) { |
a1d35437 KM |
391 | |
392 | default: | |
393 | return (1); /* XXX */ | |
394 | ||
395 | case VCHR: | |
e1b76915 JH |
396 | dev = ap->a_vp->v_rdev; |
397 | return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p); | |
a1d35437 KM |
398 | } |
399 | } | |
e2afbd7b KM |
400 | /* |
401 | * Synch buffers associated with a block device | |
402 | */ | |
403 | /* ARGSUSED */ | |
404 | int | |
405 | spec_fsync(ap) | |
406 | struct vop_fsync_args /* { | |
407 | struct vnode *a_vp; | |
408 | struct ucred *a_cred; | |
409 | int a_waitfor; | |
410 | struct proc *a_p; | |
411 | } */ *ap; | |
412 | { | |
413 | register struct vnode *vp = ap->a_vp; | |
414 | register struct buf *bp; | |
415 | struct buf *nbp; | |
a376c42f | 416 | int s; |
e2afbd7b KM |
417 | |
418 | if (vp->v_type == VCHR) | |
419 | return (0); | |
420 | /* | |
421 | * Flush all dirty buffers associated with a block device. | |
422 | */ | |
423 | loop: | |
424 | s = splbio(); | |
736c7794 KM |
425 | for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { |
426 | nbp = bp->b_vnbufs.le_next; | |
e2afbd7b KM |
427 | if ((bp->b_flags & B_BUSY)) |
428 | continue; | |
429 | if ((bp->b_flags & B_DELWRI) == 0) | |
430 | panic("spec_fsync: not dirty"); | |
431 | bremfree(bp); | |
432 | bp->b_flags |= B_BUSY; | |
433 | splx(s); | |
a376c42f | 434 | bawrite(bp); |
e2afbd7b KM |
435 | goto loop; |
436 | } | |
437 | if (ap->a_waitfor == MNT_WAIT) { | |
438 | while (vp->v_numoutput) { | |
439 | vp->v_flag |= VBWAIT; | |
440 | sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); | |
441 | } | |
442 | #ifdef DIAGNOSTIC | |
736c7794 | 443 | if (vp->v_dirtyblkhd.lh_first) { |
e2afbd7b KM |
444 | vprint("spec_fsync: dirty", vp); |
445 | goto loop; | |
446 | } | |
447 | #endif | |
448 | } | |
449 | splx(s); | |
a376c42f | 450 | return (0); |
e2afbd7b | 451 | } |
a1d35437 KM |
452 | |
453 | /* | |
454 | * Just call the device strategy routine | |
455 | */ | |
e2afbd7b KM |
456 | spec_strategy(ap) |
457 | struct vop_strategy_args /* { | |
458 | struct buf *a_bp; | |
459 | } */ *ap; | |
a1d35437 | 460 | { |
b9a4d0ff | 461 | |
e1b76915 | 462 | (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp); |
a1d35437 KM |
463 | return (0); |
464 | } | |
465 | ||
b9a4d0ff KM |
466 | /* |
467 | * This is a noop, simply returning what one has been given. | |
468 | */ | |
e2afbd7b KM |
469 | spec_bmap(ap) |
470 | struct vop_bmap_args /* { | |
471 | struct vnode *a_vp; | |
472 | daddr_t a_bn; | |
473 | struct vnode **a_vpp; | |
474 | daddr_t *a_bnp; | |
475 | } */ *ap; | |
b9a4d0ff KM |
476 | { |
477 | ||
e1b76915 JH |
478 | if (ap->a_vpp != NULL) |
479 | *ap->a_vpp = ap->a_vp; | |
480 | if (ap->a_bnp != NULL) | |
481 | *ap->a_bnp = ap->a_bn; | |
dd66b105 JSP |
482 | if (ap->a_runp != NULL) |
483 | *ap->a_runp = 0; | |
b9a4d0ff KM |
484 | return (0); |
485 | } | |
486 | ||
1c00bf64 KM |
487 | /* |
488 | * At the moment we do not do any locking. | |
489 | */ | |
ff4fb102 | 490 | /* ARGSUSED */ |
e2afbd7b KM |
491 | spec_lock(ap) |
492 | struct vop_lock_args /* { | |
493 | struct vnode *a_vp; | |
494 | } */ *ap; | |
a1d35437 | 495 | { |
a1d35437 | 496 | |
a1d35437 KM |
497 | return (0); |
498 | } | |
499 | ||
ff4fb102 | 500 | /* ARGSUSED */ |
e2afbd7b KM |
501 | spec_unlock(ap) |
502 | struct vop_unlock_args /* { | |
503 | struct vnode *a_vp; | |
504 | } */ *ap; | |
a1d35437 | 505 | { |
a1d35437 | 506 | |
a1d35437 KM |
507 | return (0); |
508 | } | |
509 | ||
a1d35437 KM |
510 | /* |
511 | * Device close routine | |
512 | */ | |
3d5d83ff | 513 | /* ARGSUSED */ |
e2afbd7b KM |
514 | spec_close(ap) |
515 | struct vop_close_args /* { | |
516 | struct vnode *a_vp; | |
517 | int a_fflag; | |
518 | struct ucred *a_cred; | |
519 | struct proc *a_p; | |
520 | } */ *ap; | |
a1d35437 | 521 | { |
406c9a0d JH |
522 | register struct vnode *vp = ap->a_vp; |
523 | dev_t dev = vp->v_rdev; | |
e15ce6a3 | 524 | int (*devclose) __P((dev_t, int, int, struct proc *)); |
e2afbd7b | 525 | int mode, error; |
a1d35437 | 526 | |
406c9a0d | 527 | switch (vp->v_type) { |
3d5d83ff KM |
528 | |
529 | case VCHR: | |
ed74b0e9 KM |
530 | /* |
531 | * Hack: a tty device that is a controlling terminal | |
532 | * has a reference from the session structure. | |
533 | * We cannot easily tell that a character device is | |
534 | * a controlling terminal, unless it is the closing | |
535 | * process' controlling terminal. In that case, | |
536 | * if the reference count is 2 (this last descriptor | |
537 | * plus the session), release the reference from the session. | |
538 | */ | |
93a50028 KM |
539 | if (vcount(vp) == 2 && ap->a_p && |
540 | vp == ap->a_p->p_session->s_ttyvp) { | |
ed74b0e9 KM |
541 | vrele(vp); |
542 | ap->a_p->p_session->s_ttyvp = NULL; | |
543 | } | |
f4b3ea62 KM |
544 | /* |
545 | * If the vnode is locked, then we are in the midst | |
546 | * of forcably closing the device, otherwise we only | |
547 | * close on last reference. | |
548 | */ | |
406c9a0d | 549 | if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) |
3d5d83ff | 550 | return (0); |
e15ce6a3 | 551 | devclose = cdevsw[major(dev)].d_close; |
1c00bf64 | 552 | mode = S_IFCHR; |
3d5d83ff KM |
553 | break; |
554 | ||
555 | case VBLK: | |
556 | /* | |
557 | * On last close of a block device (that isn't mounted) | |
558 | * we must invalidate any in core blocks, so that | |
559 | * we can, for instance, change floppy disks. | |
560 | */ | |
ede91379 | 561 | if (error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0)) |
e2afbd7b | 562 | return (error); |
3d5d83ff | 563 | /* |
f4b3ea62 KM |
564 | * We do not want to really close the device if it |
565 | * is still in use unless we are trying to close it | |
566 | * forcibly. Since every use (buffer, vnode, swap, cmap) | |
3ab57521 KM |
567 | * holds a reference to the vnode, and because we mark |
568 | * any other vnodes that alias this device, when the | |
569 | * sum of the reference counts on all the aliased | |
570 | * vnodes descends to one, we are on last close. | |
3d5d83ff | 571 | */ |
406c9a0d | 572 | if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) |
3d5d83ff | 573 | return (0); |
e15ce6a3 | 574 | devclose = bdevsw[major(dev)].d_close; |
1c00bf64 | 575 | mode = S_IFBLK; |
3d5d83ff KM |
576 | break; |
577 | ||
578 | default: | |
ad27f720 | 579 | panic("spec_close: not special"); |
3d5d83ff KM |
580 | } |
581 | ||
e1b76915 | 582 | return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p)); |
a1d35437 KM |
583 | } |
584 | ||
b9a4d0ff KM |
585 | /* |
586 | * Print out the contents of a special device vnode. | |
587 | */ | |
e2afbd7b KM |
588 | spec_print(ap) |
589 | struct vop_print_args /* { | |
590 | struct vnode *a_vp; | |
591 | } */ *ap; | |
b9a4d0ff KM |
592 | { |
593 | ||
e1b76915 JH |
594 | printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev), |
595 | minor(ap->a_vp->v_rdev)); | |
b9a4d0ff KM |
596 | } |
597 | ||
b7c4b3cc KM |
598 | /* |
599 | * Return POSIX pathconf information applicable to special devices. | |
600 | */ | |
601 | spec_pathconf(ap) | |
602 | struct vop_pathconf_args /* { | |
603 | struct vnode *a_vp; | |
604 | int a_name; | |
605 | int *a_retval; | |
606 | } */ *ap; | |
607 | { | |
608 | ||
609 | switch (ap->a_name) { | |
610 | case _PC_LINK_MAX: | |
611 | *ap->a_retval = LINK_MAX; | |
612 | return (0); | |
613 | case _PC_MAX_CANON: | |
614 | *ap->a_retval = MAX_CANON; | |
615 | return (0); | |
616 | case _PC_MAX_INPUT: | |
617 | *ap->a_retval = MAX_INPUT; | |
618 | return (0); | |
619 | case _PC_PIPE_BUF: | |
620 | *ap->a_retval = PIPE_BUF; | |
621 | return (0); | |
622 | case _PC_CHOWN_RESTRICTED: | |
623 | *ap->a_retval = 1; | |
624 | return (0); | |
625 | case _PC_VDISABLE: | |
626 | *ap->a_retval = _POSIX_VDISABLE; | |
627 | return (0); | |
628 | default: | |
629 | return (EINVAL); | |
630 | } | |
631 | /* NOTREACHED */ | |
632 | } | |
633 | ||
a4128336 KM |
634 | /* |
635 | * Special device advisory byte-level locks. | |
636 | */ | |
68a834b0 | 637 | /* ARGSUSED */ |
e2afbd7b KM |
638 | spec_advlock(ap) |
639 | struct vop_advlock_args /* { | |
640 | struct vnode *a_vp; | |
641 | caddr_t a_id; | |
642 | int a_op; | |
643 | struct flock *a_fl; | |
644 | int a_flags; | |
645 | } */ *ap; | |
a4128336 KM |
646 | { |
647 | ||
648 | return (EOPNOTSUPP); | |
649 | } | |
650 | ||
a1d35437 | 651 | /* |
7bbe72a5 KM |
652 | * Special device failed operation |
653 | */ | |
654 | spec_ebadf() | |
655 | { | |
656 | ||
657 | return (EBADF); | |
658 | } | |
659 | ||
660 | /* | |
661 | * Special device bad operation | |
a1d35437 | 662 | */ |
ad27f720 | 663 | spec_badop() |
a1d35437 KM |
664 | { |
665 | ||
ad27f720 | 666 | panic("spec_badop called"); |
59b0713e | 667 | /* NOTREACHED */ |
a1d35437 | 668 | } |