ffs_vnops.c revision 1.99.4.1 1 /* $NetBSD: ffs_vnops.c,v 1.99.4.1 2008/06/10 14:51:23 simonb Exp $ */
2
3 /*-
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Wasabi Systems, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright (c) 1982, 1986, 1989, 1993
41 * The Regents of the University of California. All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. Neither the name of the University nor the names of its contributors
52 * may be used to endorse or promote products derived from this software
53 * without specific prior written permission.
54 *
55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * SUCH DAMAGE.
66 *
67 * @(#)ffs_vnops.c 8.15 (Berkeley) 5/14/95
68 */
69
70 #include <sys/cdefs.h>
71 __KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.99.4.1 2008/06/10 14:51:23 simonb Exp $");
72
73 #if defined(_KERNEL_OPT)
74 #include "opt_ffs.h"
75 #include "opt_wapbl.h"
76 #endif
77
78 #include <sys/param.h>
79 #include <sys/systm.h>
80 #include <sys/resourcevar.h>
81 #include <sys/kernel.h>
82 #include <sys/file.h>
83 #include <sys/stat.h>
84 #include <sys/buf.h>
85 #include <sys/event.h>
86 #include <sys/proc.h>
87 #include <sys/mount.h>
88 #include <sys/vnode.h>
89 #include <sys/pool.h>
90 #include <sys/signalvar.h>
91 #include <sys/kauth.h>
92 #include <sys/wapbl.h>
93 #include <sys/fstrans.h>
94
95 #include <miscfs/fifofs/fifo.h>
96 #include <miscfs/genfs/genfs.h>
97 #include <miscfs/specfs/specdev.h>
98
99 #include <ufs/ufs/inode.h>
100 #include <ufs/ufs/dir.h>
101 #include <ufs/ufs/ufs_extern.h>
102 #include <ufs/ufs/ufsmount.h>
103 #include <ufs/ufs/ufs_wapbl.h>
104
105 #include <ufs/ffs/fs.h>
106 #include <ufs/ffs/ffs_extern.h>
107
108 #include <uvm/uvm.h>
109
110 /* Global vfs data structures for ufs. */
111 int (**ffs_vnodeop_p)(void *);
112 const struct vnodeopv_entry_desc ffs_vnodeop_entries[] = {
113 { &vop_default_desc, vn_default_error },
114 { &vop_lookup_desc, ufs_lookup }, /* lookup */
115 { &vop_create_desc, ufs_create }, /* create */
116 { &vop_whiteout_desc, ufs_whiteout }, /* whiteout */
117 { &vop_mknod_desc, ufs_mknod }, /* mknod */
118 { &vop_open_desc, ufs_open }, /* open */
119 { &vop_close_desc, ufs_close }, /* close */
120 { &vop_access_desc, ufs_access }, /* access */
121 { &vop_getattr_desc, ufs_getattr }, /* getattr */
122 { &vop_setattr_desc, ufs_setattr }, /* setattr */
123 { &vop_read_desc, ffs_read }, /* read */
124 { &vop_write_desc, ffs_write }, /* write */
125 { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */
126 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */
127 { &vop_poll_desc, ufs_poll }, /* poll */
128 { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */
129 { &vop_revoke_desc, ufs_revoke }, /* revoke */
130 { &vop_mmap_desc, ufs_mmap }, /* mmap */
131 { &vop_fsync_desc, ffs_fsync }, /* fsync */
132 { &vop_seek_desc, ufs_seek }, /* seek */
133 { &vop_remove_desc, ufs_remove }, /* remove */
134 { &vop_link_desc, ufs_link }, /* link */
135 { &vop_rename_desc, ufs_rename }, /* rename */
136 { &vop_mkdir_desc, ufs_mkdir }, /* mkdir */
137 { &vop_rmdir_desc, ufs_rmdir }, /* rmdir */
138 { &vop_symlink_desc, ufs_symlink }, /* symlink */
139 { &vop_readdir_desc, ufs_readdir }, /* readdir */
140 { &vop_readlink_desc, ufs_readlink }, /* readlink */
141 { &vop_abortop_desc, ufs_abortop }, /* abortop */
142 { &vop_inactive_desc, ufs_inactive }, /* inactive */
143 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */
144 { &vop_lock_desc, ffs_lock }, /* lock */
145 { &vop_unlock_desc, ffs_unlock }, /* unlock */
146 { &vop_bmap_desc, ufs_bmap }, /* bmap */
147 { &vop_strategy_desc, ufs_strategy }, /* strategy */
148 { &vop_print_desc, ufs_print }, /* print */
149 { &vop_islocked_desc, ffs_islocked }, /* islocked */
150 { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */
151 { &vop_advlock_desc, ufs_advlock }, /* advlock */
152 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
153 { &vop_getpages_desc, genfs_getpages }, /* getpages */
154 { &vop_putpages_desc, genfs_putpages }, /* putpages */
155 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */
156 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */
157 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */
158 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */
159 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */
160 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */
161 { NULL, NULL }
162 };
163 const struct vnodeopv_desc ffs_vnodeop_opv_desc =
164 { &ffs_vnodeop_p, ffs_vnodeop_entries };
165
166 int (**ffs_specop_p)(void *);
167 const struct vnodeopv_entry_desc ffs_specop_entries[] = {
168 { &vop_default_desc, vn_default_error },
169 { &vop_lookup_desc, spec_lookup }, /* lookup */
170 { &vop_create_desc, spec_create }, /* create */
171 { &vop_mknod_desc, spec_mknod }, /* mknod */
172 { &vop_open_desc, spec_open }, /* open */
173 { &vop_close_desc, ufsspec_close }, /* close */
174 { &vop_access_desc, ufs_access }, /* access */
175 { &vop_getattr_desc, ufs_getattr }, /* getattr */
176 { &vop_setattr_desc, ufs_setattr }, /* setattr */
177 { &vop_read_desc, ufsspec_read }, /* read */
178 { &vop_write_desc, ufsspec_write }, /* write */
179 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */
180 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */
181 { &vop_poll_desc, spec_poll }, /* poll */
182 { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */
183 { &vop_revoke_desc, spec_revoke }, /* revoke */
184 { &vop_mmap_desc, spec_mmap }, /* mmap */
185 { &vop_fsync_desc, ffs_fsync }, /* fsync */
186 { &vop_seek_desc, spec_seek }, /* seek */
187 { &vop_remove_desc, spec_remove }, /* remove */
188 { &vop_link_desc, spec_link }, /* link */
189 { &vop_rename_desc, spec_rename }, /* rename */
190 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */
191 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */
192 { &vop_symlink_desc, spec_symlink }, /* symlink */
193 { &vop_readdir_desc, spec_readdir }, /* readdir */
194 { &vop_readlink_desc, spec_readlink }, /* readlink */
195 { &vop_abortop_desc, spec_abortop }, /* abortop */
196 { &vop_inactive_desc, ufs_inactive }, /* inactive */
197 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */
198 { &vop_lock_desc, ffs_lock }, /* lock */
199 { &vop_unlock_desc, ffs_unlock }, /* unlock */
200 { &vop_bmap_desc, spec_bmap }, /* bmap */
201 { &vop_strategy_desc, spec_strategy }, /* strategy */
202 { &vop_print_desc, ufs_print }, /* print */
203 { &vop_islocked_desc, ffs_islocked }, /* islocked */
204 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
205 { &vop_advlock_desc, spec_advlock }, /* advlock */
206 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
207 { &vop_getpages_desc, spec_getpages }, /* getpages */
208 { &vop_putpages_desc, spec_putpages }, /* putpages */
209 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */
210 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */
211 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */
212 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */
213 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */
214 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */
215 { NULL, NULL }
216 };
217 const struct vnodeopv_desc ffs_specop_opv_desc =
218 { &ffs_specop_p, ffs_specop_entries };
219
220 int (**ffs_fifoop_p)(void *);
221 const struct vnodeopv_entry_desc ffs_fifoop_entries[] = {
222 { &vop_default_desc, vn_default_error },
223 { &vop_lookup_desc, fifo_lookup }, /* lookup */
224 { &vop_create_desc, fifo_create }, /* create */
225 { &vop_mknod_desc, fifo_mknod }, /* mknod */
226 { &vop_open_desc, fifo_open }, /* open */
227 { &vop_close_desc, ufsfifo_close }, /* close */
228 { &vop_access_desc, ufs_access }, /* access */
229 { &vop_getattr_desc, ufs_getattr }, /* getattr */
230 { &vop_setattr_desc, ufs_setattr }, /* setattr */
231 { &vop_read_desc, ufsfifo_read }, /* read */
232 { &vop_write_desc, ufsfifo_write }, /* write */
233 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
234 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */
235 { &vop_poll_desc, fifo_poll }, /* poll */
236 { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */
237 { &vop_revoke_desc, fifo_revoke }, /* revoke */
238 { &vop_mmap_desc, fifo_mmap }, /* mmap */
239 { &vop_fsync_desc, ffs_fsync }, /* fsync */
240 { &vop_seek_desc, fifo_seek }, /* seek */
241 { &vop_remove_desc, fifo_remove }, /* remove */
242 { &vop_link_desc, fifo_link }, /* link */
243 { &vop_rename_desc, fifo_rename }, /* rename */
244 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */
245 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */
246 { &vop_symlink_desc, fifo_symlink }, /* symlink */
247 { &vop_readdir_desc, fifo_readdir }, /* readdir */
248 { &vop_readlink_desc, fifo_readlink }, /* readlink */
249 { &vop_abortop_desc, fifo_abortop }, /* abortop */
250 { &vop_inactive_desc, ufs_inactive }, /* inactive */
251 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */
252 { &vop_lock_desc, ffs_lock }, /* lock */
253 { &vop_unlock_desc, ffs_unlock }, /* unlock */
254 { &vop_bmap_desc, fifo_bmap }, /* bmap */
255 { &vop_strategy_desc, fifo_strategy }, /* strategy */
256 { &vop_print_desc, ufs_print }, /* print */
257 { &vop_islocked_desc, ffs_islocked }, /* islocked */
258 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */
259 { &vop_advlock_desc, fifo_advlock }, /* advlock */
260 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
261 { &vop_putpages_desc, fifo_putpages }, /* putpages */
262 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */
263 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */
264 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */
265 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */
266 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */
267 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */
268 { NULL, NULL }
269 };
270 const struct vnodeopv_desc ffs_fifoop_opv_desc =
271 { &ffs_fifoop_p, ffs_fifoop_entries };
272
273 #include <ufs/ufs/ufs_readwrite.c>
274
275 int
276 ffs_fsync(void *v)
277 {
278 struct vop_fsync_args /* {
279 struct vnode *a_vp;
280 kauth_cred_t a_cred;
281 int a_flags;
282 off_t a_offlo;
283 off_t a_offhi;
284 struct lwp *a_l;
285 } */ *ap = v;
286 struct buf *bp;
287 int num, error, i;
288 struct indir ia[NIADDR + 1];
289 int bsize;
290 daddr_t blk_high;
291 struct vnode *vp;
292 #ifdef WAPBL
293 struct mount *mp;
294 #endif
295
296 vp = ap->a_vp;
297
298 fstrans_start(vp->v_mount, FSTRANS_LAZY);
299 /*
300 * XXX no easy way to sync a range in a file with softdep.
301 */
302 if ((ap->a_offlo == 0 && ap->a_offhi == 0) || DOINGSOFTDEP(vp) ||
303 (vp->v_type != VREG)) {
304 error = ffs_full_fsync(vp, ap->a_flags);
305 goto out;
306 }
307
308 bsize = vp->v_mount->mnt_stat.f_iosize;
309 blk_high = ap->a_offhi / bsize;
310 if (ap->a_offhi % bsize != 0)
311 blk_high++;
312
313 /*
314 * First, flush all pages in range.
315 */
316
317 mutex_enter(&vp->v_interlock);
318 error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo),
319 round_page(ap->a_offhi), PGO_CLEANIT |
320 ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0));
321 if (error) {
322 goto out;
323 }
324
325 #ifdef WAPBL
326 mp = wapbl_vptomp(vp);
327 if (mp->mnt_wapbl) {
328 if (ap->a_flags & FSYNC_DATAONLY) {
329 fstrans_done(vp->v_mount);
330 return 0;
331 }
332 error = 0;
333 if (vp->v_tag == VT_UFS && VTOI(vp)->i_flag &
334 (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY |
335 IN_MODIFIED | IN_ACCESSED)) {
336 error = UFS_WAPBL_BEGIN(mp);
337 if (error) {
338 fstrans_done(vp->v_mount);
339 return error;
340 }
341 error = ffs_update(vp, NULL, NULL,
342 (ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0);
343 UFS_WAPBL_END(mp);
344 }
345 if (error || (ap->a_flags & FSYNC_NOLOG)) {
346 fstrans_done(vp->v_mount);
347 return error;
348 }
349 error = wapbl_flush(mp->mnt_wapbl, 0);
350 fstrans_done(vp->v_mount);
351 return error;
352 }
353 #endif /* WAPBL */
354
355 /*
356 * Then, flush indirect blocks.
357 */
358
359 if (blk_high >= NDADDR) {
360 error = ufs_getlbns(vp, blk_high, ia, &num);
361 if (error)
362 goto out;
363
364 mutex_enter(&bufcache_lock);
365 for (i = 0; i < num; i++) {
366 if ((bp = incore(vp, ia[i].in_lbn)) == NULL)
367 continue;
368 if ((bp->b_cflags & BC_BUSY) != 0 ||
369 (bp->b_oflags & BO_DELWRI) == 0)
370 continue;
371 bp->b_cflags |= BC_BUSY | BC_VFLUSH;
372 mutex_exit(&bufcache_lock);
373 bawrite(bp);
374 mutex_enter(&bufcache_lock);
375 }
376 mutex_exit(&bufcache_lock);
377 }
378
379 if (ap->a_flags & FSYNC_WAIT) {
380 mutex_enter(&vp->v_interlock);
381 while (vp->v_numoutput > 0)
382 cv_wait(&vp->v_cv, &vp->v_interlock);
383 mutex_exit(&vp->v_interlock);
384 }
385
386 error = ffs_update(vp, NULL, NULL,
387 ((ap->a_flags & (FSYNC_WAIT | FSYNC_DATAONLY)) == FSYNC_WAIT)
388 ? UPDATE_WAIT : 0);
389
390 if (error == 0 && ap->a_flags & FSYNC_CACHE) {
391 int l = 0;
392 VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE,
393 curlwp->l_cred);
394 }
395
396 out:
397 fstrans_done(vp->v_mount);
398 return error;
399 }
400
401 /*
402 * Synch an open file.
403 */
404 /* ARGSUSED */
405 int
406 ffs_full_fsync(struct vnode *vp, int flags)
407 {
408 struct buf *bp, *nbp;
409 int error, passes, skipmeta, inodedeps_only, waitfor;
410 struct mount *mp;
411
412 error = 0;
413
414 if (vp->v_type == VBLK &&
415 vp->v_specmountpoint != NULL &&
416 (vp->v_specmountpoint->mnt_flag & MNT_SOFTDEP))
417 softdep_fsync_mountdev(vp);
418
419 mutex_enter(&vp->v_interlock);
420
421 inodedeps_only = DOINGSOFTDEP(vp) && (flags & FSYNC_RECLAIM)
422 && UVM_OBJ_IS_CLEAN(&vp->v_uobj) && LIST_EMPTY(&vp->v_dirtyblkhd);
423
424 /*
425 * Flush all dirty data associated with a vnode.
426 */
427
428 mp = NULL;
429 if (vp->v_type == VREG || vp->v_type == VBLK) {
430 if ((flags & FSYNC_VFS) != 0)
431 mp = vp->v_specmountpoint;
432 else
433 mp = vp->v_mount;
434 error = VOP_PUTPAGES(vp, 0, 0, PGO_ALLPAGES | PGO_CLEANIT |
435 ((flags & FSYNC_WAIT) ? PGO_SYNCIO : 0) |
436 (fstrans_getstate(mp) == FSTRANS_SUSPENDING ?
437 PGO_FREE : 0));
438 if (error)
439 return error;
440 } else
441 mutex_exit(&vp->v_interlock);
442
443 #ifdef WAPBL
444 mp = wapbl_vptomp(vp); /* XXXXXX anti-kern/38057 hack */
445 if (mp && mp->mnt_wapbl) {
446 error = 0;
447 if (flags & FSYNC_DATAONLY)
448 return error;
449
450 if (VTOI(vp)->i_flag &
451 (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY |
452 IN_MODIFIED | IN_ACCESSED)) {
453 error = UFS_WAPBL_BEGIN(mp);
454 if (error)
455 return error;
456 error = ffs_update(vp, NULL, NULL,
457 (flags & FSYNC_WAIT) ? UPDATE_WAIT : 0);
458 UFS_WAPBL_END(mp);
459 }
460 if (error || (flags & FSYNC_NOLOG))
461 return error;
462 /*
463 * Don't flush the log if the vnode being flushed
464 * contains no dirty buffers that could be in the log.
465 */
466 if (!((flags & FSYNC_RECLAIM) &&
467 LIST_EMPTY(&vp->v_dirtyblkhd))) {
468 error = wapbl_flush(mp->mnt_wapbl, 0);
469 if (error)
470 return error;
471 }
472
473 /*
474 * XXX temporary workaround for "dirty bufs" panic in
475 * vinvalbuf. need a full fix for the v_numoutput
476 * waiters issues.
477 */
478 if (flags & FSYNC_WAIT) {
479 mutex_enter(&vp->v_interlock);
480 while (vp->v_numoutput)
481 cv_wait(&vp->v_cv, &vp->v_interlock);
482 mutex_exit(&vp->v_interlock);
483 }
484
485 return error;
486 }
487 #endif /* WAPBL */
488
489 passes = NIADDR + 1;
490 skipmeta = 0;
491 if (flags & FSYNC_WAIT)
492 skipmeta = 1;
493
494 loop:
495 mutex_enter(&bufcache_lock);
496 LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) {
497 bp->b_cflags &= ~BC_SCANNED;
498 }
499 for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
500 nbp = LIST_NEXT(bp, b_vnbufs);
501 if (bp->b_cflags & (BC_BUSY | BC_SCANNED))
502 continue;
503 if ((bp->b_oflags & BO_DELWRI) == 0)
504 panic("ffs_fsync: not dirty");
505 if (skipmeta && bp->b_lblkno < 0)
506 continue;
507 bp->b_cflags |= BC_BUSY | BC_VFLUSH | BC_SCANNED;
508 mutex_exit(&bufcache_lock);
509 /*
510 * On our final pass through, do all I/O synchronously
511 * so that we can find out if our flush is failing
512 * because of write errors.
513 */
514 if (passes > 0 || !(flags & FSYNC_WAIT))
515 (void) bawrite(bp);
516 else if ((error = bwrite(bp)) != 0)
517 return (error);
518 /*
519 * Since we unlocked during the I/O, we need
520 * to start from a known point.
521 */
522 mutex_enter(&bufcache_lock);
523 nbp = LIST_FIRST(&vp->v_dirtyblkhd);
524 }
525 mutex_exit(&bufcache_lock);
526 if (skipmeta) {
527 skipmeta = 0;
528 goto loop;
529 }
530
531 if (flags & FSYNC_WAIT) {
532 mutex_enter(&vp->v_interlock);
533 while (vp->v_numoutput) {
534 cv_wait(&vp->v_cv, &vp->v_interlock);
535 }
536 mutex_exit(&vp->v_interlock);
537
538 /*
539 * Ensure that any filesystem metadata associated
540 * with the vnode has been written.
541 */
542 if ((error = softdep_sync_metadata(vp)) != 0)
543 return (error);
544
545 if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
546 /*
547 * Block devices associated with filesystems may
548 * have new I/O requests posted for them even if
549 * the vnode is locked, so no amount of trying will
550 * get them clean. Thus we give block devices a
551 * good effort, then just give up. For all other file
552 * types, go around and try again until it is clean.
553 */
554 if (passes > 0) {
555 passes--;
556 goto loop;
557 }
558 #ifdef DIAGNOSTIC
559 if (vp->v_type != VBLK)
560 vprint("ffs_fsync: dirty", vp);
561 #endif
562 }
563 }
564
565 if (inodedeps_only)
566 waitfor = 0;
567 else
568 waitfor = (flags & FSYNC_WAIT) ? UPDATE_WAIT : 0;
569
570 if (vp->v_tag == VT_UFS)
571 error = ffs_update(vp, NULL, NULL, waitfor);
572 else {
573 KASSERT(vp->v_type == VBLK);
574 KASSERT((flags & FSYNC_VFS) != 0);
575 }
576
577 if (error == 0 && flags & FSYNC_CACHE) {
578 int i = 0;
579 if ((flags & FSYNC_VFS) == 0)
580 vp = VTOI(vp)->i_devvp;
581 VOP_IOCTL(vp, DIOCCACHESYNC, &i, FWRITE, curlwp->l_cred);
582 }
583
584 return error;
585 }
586
587 /*
588 * Reclaim an inode so that it can be used for other purposes.
589 */
590 int
591 ffs_reclaim(void *v)
592 {
593 struct vop_reclaim_args /* {
594 struct vnode *a_vp;
595 struct lwp *a_l;
596 } */ *ap = v;
597 struct vnode *vp = ap->a_vp;
598 struct inode *ip = VTOI(vp);
599 struct mount *mp = vp->v_mount;
600 struct ufsmount *ump = ip->i_ump;
601 void *data;
602 int error;
603
604 fstrans_start(mp, FSTRANS_LAZY);
605 if ((error = ufs_reclaim(vp)) != 0) {
606 fstrans_done(mp);
607 return (error);
608 }
609 if (ip->i_din.ffs1_din != NULL) {
610 if (ump->um_fstype == UFS1)
611 pool_cache_put(ffs_dinode1_cache, ip->i_din.ffs1_din);
612 else
613 pool_cache_put(ffs_dinode2_cache, ip->i_din.ffs2_din);
614 }
615 /*
616 * To interlock with ffs_sync().
617 */
618 genfs_node_destroy(vp);
619 mutex_enter(&vp->v_interlock);
620 data = vp->v_data;
621 vp->v_data = NULL;
622 mutex_exit(&vp->v_interlock);
623
624 /*
625 * XXX MFS ends up here, too, to free an inode. Should we create
626 * XXX a separate pool for MFS inodes?
627 */
628 pool_cache_put(ffs_inode_cache, data);
629 fstrans_done(mp);
630 return (0);
631 }
632
633 #if 0
634 int
635 ffs_getpages(void *v)
636 {
637 struct vop_getpages_args /* {
638 struct vnode *a_vp;
639 voff_t a_offset;
640 struct vm_page **a_m;
641 int *a_count;
642 int a_centeridx;
643 vm_prot_t a_access_type;
644 int a_advice;
645 int a_flags;
646 } */ *ap = v;
647 struct vnode *vp = ap->a_vp;
648 struct inode *ip = VTOI(vp);
649 struct fs *fs = ip->i_fs;
650
651 /*
652 * don't allow a softdep write to create pages for only part of a block.
653 * the dependency tracking requires that all pages be in memory for
654 * a block involved in a dependency.
655 */
656
657 if (ap->a_flags & PGO_OVERWRITE &&
658 (blkoff(fs, ap->a_offset) != 0 ||
659 blkoff(fs, *ap->a_count << PAGE_SHIFT) != 0) &&
660 DOINGSOFTDEP(ap->a_vp)) {
661 if ((ap->a_flags & PGO_LOCKED) == 0) {
662 mutex_exit(&vp->v_interlock);
663 }
664 return EINVAL;
665 }
666 return genfs_getpages(v);
667 }
668 #endif
669
670 /*
671 * Return the last logical file offset that should be written for this file
672 * if we're doing a write that ends at "size".
673 */
674
675 void
676 ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags)
677 {
678 struct inode *ip = VTOI(vp);
679 struct fs *fs = ip->i_fs;
680 daddr_t olbn, nlbn;
681
682 olbn = lblkno(fs, ip->i_size);
683 nlbn = lblkno(fs, size);
684 if (nlbn < NDADDR && olbn <= nlbn) {
685 *eobp = fragroundup(fs, size);
686 } else {
687 *eobp = blkroundup(fs, size);
688 }
689 }
690
691 int
692 ffs_openextattr(void *v)
693 {
694 struct vop_openextattr_args /* {
695 struct vnode *a_vp;
696 kauth_cred_t a_cred;
697 struct proc *a_p;
698 } */ *ap = v;
699 struct inode *ip = VTOI(ap->a_vp);
700 struct fs *fs = ip->i_fs;
701
702 /* Not supported for UFS1 file systems. */
703 if (fs->fs_magic == FS_UFS1_MAGIC)
704 return (EOPNOTSUPP);
705
706 /* XXX Not implemented for UFS2 file systems. */
707 return (EOPNOTSUPP);
708 }
709
710 int
711 ffs_closeextattr(void *v)
712 {
713 struct vop_closeextattr_args /* {
714 struct vnode *a_vp;
715 int a_commit;
716 kauth_cred_t a_cred;
717 struct proc *a_p;
718 } */ *ap = v;
719 struct inode *ip = VTOI(ap->a_vp);
720 struct fs *fs = ip->i_fs;
721
722 /* Not supported for UFS1 file systems. */
723 if (fs->fs_magic == FS_UFS1_MAGIC)
724 return (EOPNOTSUPP);
725
726 /* XXX Not implemented for UFS2 file systems. */
727 return (EOPNOTSUPP);
728 }
729
730 int
731 ffs_getextattr(void *v)
732 {
733 struct vop_getextattr_args /* {
734 struct vnode *a_vp;
735 int a_attrnamespace;
736 const char *a_name;
737 struct uio *a_uio;
738 size_t *a_size;
739 kauth_cred_t a_cred;
740 struct proc *a_p;
741 } */ *ap = v;
742 struct vnode *vp = ap->a_vp;
743 struct inode *ip = VTOI(vp);
744 struct fs *fs = ip->i_fs;
745
746 if (fs->fs_magic == FS_UFS1_MAGIC) {
747 #ifdef UFS_EXTATTR
748 int error;
749
750 fstrans_start(vp->v_mount, FSTRANS_SHARED);
751 error = ufs_getextattr(ap);
752 fstrans_done(vp->v_mount);
753 return error;
754 #else
755 return (EOPNOTSUPP);
756 #endif
757 }
758
759 /* XXX Not implemented for UFS2 file systems. */
760 return (EOPNOTSUPP);
761 }
762
763 int
764 ffs_setextattr(void *v)
765 {
766 struct vop_setextattr_args /* {
767 struct vnode *a_vp;
768 int a_attrnamespace;
769 const char *a_name;
770 struct uio *a_uio;
771 kauth_cred_t a_cred;
772 struct proc *a_p;
773 } */ *ap = v;
774 struct vnode *vp = ap->a_vp;
775 struct inode *ip = VTOI(vp);
776 struct fs *fs = ip->i_fs;
777
778 if (fs->fs_magic == FS_UFS1_MAGIC) {
779 #ifdef UFS_EXTATTR
780 int error;
781
782 fstrans_start(vp->v_mount, FSTRANS_SHARED);
783 error = ufs_setextattr(ap);
784 fstrans_done(vp->v_mount);
785 return error;
786 #else
787 return (EOPNOTSUPP);
788 #endif
789 }
790
791 /* XXX Not implemented for UFS2 file systems. */
792 return (EOPNOTSUPP);
793 }
794
795 int
796 ffs_listextattr(void *v)
797 {
798 struct vop_listextattr_args /* {
799 struct vnode *a_vp;
800 int a_attrnamespace;
801 struct uio *a_uio;
802 size_t *a_size;
803 kauth_cred_t a_cred;
804 struct proc *a_p;
805 } */ *ap = v;
806 struct inode *ip = VTOI(ap->a_vp);
807 struct fs *fs = ip->i_fs;
808
809 /* Not supported for UFS1 file systems. */
810 if (fs->fs_magic == FS_UFS1_MAGIC)
811 return (EOPNOTSUPP);
812
813 /* XXX Not implemented for UFS2 file systems. */
814 return (EOPNOTSUPP);
815 }
816
817 int
818 ffs_deleteextattr(void *v)
819 {
820 struct vop_deleteextattr_args /* {
821 struct vnode *a_vp;
822 int a_attrnamespace;
823 kauth_cred_t a_cred;
824 struct proc *a_p;
825 } */ *ap = v;
826 struct vnode *vp = ap->a_vp;
827 struct inode *ip = VTOI(vp);
828 struct fs *fs = ip->i_fs;
829
830 if (fs->fs_magic == FS_UFS1_MAGIC) {
831 #ifdef UFS_EXTATTR
832 int error;
833
834 fstrans_start(vp->v_mount, FSTRANS_SHARED);
835 error = ufs_deleteextattr(ap);
836 fstrans_done(vp->v_mount);
837 return error;
838 #else
839 return (EOPNOTSUPP);
840 #endif
841 }
842
843 /* XXX Not implemented for UFS2 file systems. */
844 return (EOPNOTSUPP);
845 }
846
847 /*
848 * Lock the node.
849 */
850 int
851 ffs_lock(void *v)
852 {
853 struct vop_lock_args /* {
854 struct vnode *a_vp;
855 int a_flags;
856 } */ *ap = v;
857 struct vnode *vp = ap->a_vp;
858 struct mount *mp = vp->v_mount;
859 struct vnlock *lkp;
860 int flags = ap->a_flags;
861 int result;
862
863 if ((flags & LK_INTERLOCK) != 0) {
864 mutex_exit(&vp->v_interlock);
865 flags &= ~LK_INTERLOCK;
866 }
867
868 /*
869 * Fake lock during file system suspension.
870 */
871 if ((vp->v_type == VREG || vp->v_type == VDIR) &&
872 fstrans_is_owner(mp) &&
873 fstrans_getstate(mp) == FSTRANS_SUSPENDING) {
874 return 0;
875 }
876
877 for (;;) {
878 lkp = vp->v_vnlock;
879 result = vlockmgr(lkp, flags);
880 if (lkp == vp->v_vnlock || result != 0)
881 return result;
882 /*
883 * Apparent success, except that the vnode mutated between
884 * snapshot file vnode and regular file vnode while this
885 * thread slept. The lock currently held is not the right
886 * lock. Release it, and try to get the new lock.
887 */
888 (void) vlockmgr(lkp, LK_RELEASE);
889 }
890 }
891
892 /*
893 * Unlock the node.
894 */
895 int
896 ffs_unlock(void *v)
897 {
898 struct vop_unlock_args /* {
899 struct vnode *a_vp;
900 int a_flags;
901 } */ *ap = v;
902 struct vnode *vp = ap->a_vp;
903 struct mount *mp = vp->v_mount;
904
905 KASSERT(ap->a_flags == 0);
906
907 /*
908 * Fake unlock during file system suspension.
909 */
910 if ((vp->v_type == VREG || vp->v_type == VDIR) &&
911 fstrans_is_owner(mp) &&
912 fstrans_getstate(mp) == FSTRANS_SUSPENDING) {
913 return 0;
914 }
915 return (vlockmgr(vp->v_vnlock, LK_RELEASE));
916 }
917
918 /*
919 * Return whether or not the node is locked.
920 */
921 int
922 ffs_islocked(void *v)
923 {
924 struct vop_islocked_args /* {
925 struct vnode *a_vp;
926 } */ *ap = v;
927 struct vnode *vp = ap->a_vp;
928
929 return (vlockstatus(vp->v_vnlock));
930 }
931