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