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