ffs_vnops.c revision 1.100 1 /* $NetBSD: ffs_vnops.c,v 1.100 2008/07/31 05:38:06 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 *
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.100 2008/07/31 05:38:06 simonb 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 if ((flags & FSYNC_VFS) != 0 && vp->v_specmountpoint != NULL)
427 mp = vp->v_specmountpoint;
428 else
429 mp = vp->v_mount;
430 error = VOP_PUTPAGES(vp, 0, 0, PGO_ALLPAGES | PGO_CLEANIT |
431 ((flags & FSYNC_WAIT) ? PGO_SYNCIO : 0) |
432 (fstrans_getstate(mp) == FSTRANS_SUSPENDING ?
433 PGO_FREE : 0));
434 if (error)
435 return error;
436 } else {
437 mp = vp->v_mount;
438 mutex_exit(&vp->v_interlock);
439 }
440
441 #ifdef WAPBL
442 if (mp && mp->mnt_wapbl) {
443 error = 0;
444 if (flags & FSYNC_DATAONLY)
445 return error;
446
447 if (VTOI(vp) && (VTOI(vp)->i_flag &
448 (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY |
449 IN_MODIFIED | IN_ACCESSED))) {
450 error = UFS_WAPBL_BEGIN(mp);
451 if (error)
452 return error;
453 error = ffs_update(vp, NULL, NULL,
454 (flags & FSYNC_WAIT) ? UPDATE_WAIT : 0);
455 UFS_WAPBL_END(mp);
456 }
457 if (error || (flags & FSYNC_NOLOG))
458 return error;
459 /*
460 * Don't flush the log if the vnode being flushed
461 * contains no dirty buffers that could be in the log.
462 */
463 if (!((flags & FSYNC_RECLAIM) &&
464 LIST_EMPTY(&vp->v_dirtyblkhd))) {
465 error = wapbl_flush(mp->mnt_wapbl, 0);
466 if (error)
467 return error;
468 }
469
470 /*
471 * XXX temporary workaround for "dirty bufs" panic in
472 * vinvalbuf. need a full fix for the v_numoutput
473 * waiters issues.
474 */
475 if (flags & FSYNC_WAIT) {
476 mutex_enter(&vp->v_interlock);
477 while (vp->v_numoutput)
478 cv_wait(&vp->v_cv, &vp->v_interlock);
479 mutex_exit(&vp->v_interlock);
480 }
481
482 return error;
483 }
484 #endif /* WAPBL */
485
486 passes = NIADDR + 1;
487 skipmeta = 0;
488 if (flags & FSYNC_WAIT)
489 skipmeta = 1;
490
491 loop:
492 mutex_enter(&bufcache_lock);
493 LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) {
494 bp->b_cflags &= ~BC_SCANNED;
495 }
496 for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
497 nbp = LIST_NEXT(bp, b_vnbufs);
498 if (bp->b_cflags & (BC_BUSY | BC_SCANNED))
499 continue;
500 if ((bp->b_oflags & BO_DELWRI) == 0)
501 panic("ffs_fsync: not dirty");
502 if (skipmeta && bp->b_lblkno < 0)
503 continue;
504 bp->b_cflags |= BC_BUSY | BC_VFLUSH | BC_SCANNED;
505 mutex_exit(&bufcache_lock);
506 /*
507 * On our final pass through, do all I/O synchronously
508 * so that we can find out if our flush is failing
509 * because of write errors.
510 */
511 if (passes > 0 || !(flags & FSYNC_WAIT))
512 (void) bawrite(bp);
513 else if ((error = bwrite(bp)) != 0)
514 return (error);
515 /*
516 * Since we unlocked during the I/O, we need
517 * to start from a known point.
518 */
519 mutex_enter(&bufcache_lock);
520 nbp = LIST_FIRST(&vp->v_dirtyblkhd);
521 }
522 mutex_exit(&bufcache_lock);
523 if (skipmeta) {
524 skipmeta = 0;
525 goto loop;
526 }
527
528 if (flags & FSYNC_WAIT) {
529 mutex_enter(&vp->v_interlock);
530 while (vp->v_numoutput) {
531 cv_wait(&vp->v_cv, &vp->v_interlock);
532 }
533 mutex_exit(&vp->v_interlock);
534
535 /*
536 * Ensure that any filesystem metadata associated
537 * with the vnode has been written.
538 */
539 if ((error = softdep_sync_metadata(vp)) != 0)
540 return (error);
541
542 if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
543 /*
544 * Block devices associated with filesystems may
545 * have new I/O requests posted for them even if
546 * the vnode is locked, so no amount of trying will
547 * get them clean. Thus we give block devices a
548 * good effort, then just give up. For all other file
549 * types, go around and try again until it is clean.
550 */
551 if (passes > 0) {
552 passes--;
553 goto loop;
554 }
555 #ifdef DIAGNOSTIC
556 if (vp->v_type != VBLK)
557 vprint("ffs_fsync: dirty", vp);
558 #endif
559 }
560 }
561
562 if (inodedeps_only)
563 waitfor = 0;
564 else
565 waitfor = (flags & FSYNC_WAIT) ? UPDATE_WAIT : 0;
566
567 if (vp->v_tag == VT_UFS)
568 error = ffs_update(vp, NULL, NULL, waitfor);
569 else {
570 KASSERT(vp->v_type == VBLK);
571 KASSERT((flags & FSYNC_VFS) != 0);
572 }
573
574 if (error == 0 && flags & FSYNC_CACHE) {
575 int i = 0;
576 if ((flags & FSYNC_VFS) == 0) {
577 KASSERT(VTOI(vp) != NULL);
578 vp = VTOI(vp)->i_devvp;
579 }
580 VOP_IOCTL(vp, DIOCCACHESYNC, &i, FWRITE, curlwp->l_cred);
581 }
582
583 return error;
584 }
585
586 /*
587 * Reclaim an inode so that it can be used for other purposes.
588 */
589 int
590 ffs_reclaim(void *v)
591 {
592 struct vop_reclaim_args /* {
593 struct vnode *a_vp;
594 struct lwp *a_l;
595 } */ *ap = v;
596 struct vnode *vp = ap->a_vp;
597 struct inode *ip = VTOI(vp);
598 struct mount *mp = vp->v_mount;
599 struct ufsmount *ump = ip->i_ump;
600 void *data;
601 int error;
602
603 fstrans_start(mp, FSTRANS_LAZY);
604 if ((error = ufs_reclaim(vp)) != 0) {
605 fstrans_done(mp);
606 return (error);
607 }
608 if (ip->i_din.ffs1_din != NULL) {
609 if (ump->um_fstype == UFS1)
610 pool_cache_put(ffs_dinode1_cache, ip->i_din.ffs1_din);
611 else
612 pool_cache_put(ffs_dinode2_cache, ip->i_din.ffs2_din);
613 }
614 /*
615 * To interlock with ffs_sync().
616 */
617 genfs_node_destroy(vp);
618 mutex_enter(&vp->v_interlock);
619 data = vp->v_data;
620 vp->v_data = NULL;
621 mutex_exit(&vp->v_interlock);
622
623 /*
624 * XXX MFS ends up here, too, to free an inode. Should we create
625 * XXX a separate pool for MFS inodes?
626 */
627 pool_cache_put(ffs_inode_cache, data);
628 fstrans_done(mp);
629 return (0);
630 }
631
632 #if 0
633 int
634 ffs_getpages(void *v)
635 {
636 struct vop_getpages_args /* {
637 struct vnode *a_vp;
638 voff_t a_offset;
639 struct vm_page **a_m;
640 int *a_count;
641 int a_centeridx;
642 vm_prot_t a_access_type;
643 int a_advice;
644 int a_flags;
645 } */ *ap = v;
646 struct vnode *vp = ap->a_vp;
647 struct inode *ip = VTOI(vp);
648 struct fs *fs = ip->i_fs;
649
650 /*
651 * don't allow a softdep write to create pages for only part of a block.
652 * the dependency tracking requires that all pages be in memory for
653 * a block involved in a dependency.
654 */
655
656 if (ap->a_flags & PGO_OVERWRITE &&
657 (blkoff(fs, ap->a_offset) != 0 ||
658 blkoff(fs, *ap->a_count << PAGE_SHIFT) != 0) &&
659 DOINGSOFTDEP(ap->a_vp)) {
660 if ((ap->a_flags & PGO_LOCKED) == 0) {
661 mutex_exit(&vp->v_interlock);
662 }
663 return EINVAL;
664 }
665 return genfs_getpages(v);
666 }
667 #endif
668
669 /*
670 * Return the last logical file offset that should be written for this file
671 * if we're doing a write that ends at "size".
672 */
673
674 void
675 ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags)
676 {
677 struct inode *ip = VTOI(vp);
678 struct fs *fs = ip->i_fs;
679 daddr_t olbn, nlbn;
680
681 olbn = lblkno(fs, ip->i_size);
682 nlbn = lblkno(fs, size);
683 if (nlbn < NDADDR && olbn <= nlbn) {
684 *eobp = fragroundup(fs, size);
685 } else {
686 *eobp = blkroundup(fs, size);
687 }
688 }
689
690 int
691 ffs_openextattr(void *v)
692 {
693 struct vop_openextattr_args /* {
694 struct vnode *a_vp;
695 kauth_cred_t a_cred;
696 struct proc *a_p;
697 } */ *ap = v;
698 struct inode *ip = VTOI(ap->a_vp);
699 struct fs *fs = ip->i_fs;
700
701 /* Not supported for UFS1 file systems. */
702 if (fs->fs_magic == FS_UFS1_MAGIC)
703 return (EOPNOTSUPP);
704
705 /* XXX Not implemented for UFS2 file systems. */
706 return (EOPNOTSUPP);
707 }
708
709 int
710 ffs_closeextattr(void *v)
711 {
712 struct vop_closeextattr_args /* {
713 struct vnode *a_vp;
714 int a_commit;
715 kauth_cred_t a_cred;
716 struct proc *a_p;
717 } */ *ap = v;
718 struct inode *ip = VTOI(ap->a_vp);
719 struct fs *fs = ip->i_fs;
720
721 /* Not supported for UFS1 file systems. */
722 if (fs->fs_magic == FS_UFS1_MAGIC)
723 return (EOPNOTSUPP);
724
725 /* XXX Not implemented for UFS2 file systems. */
726 return (EOPNOTSUPP);
727 }
728
729 int
730 ffs_getextattr(void *v)
731 {
732 struct vop_getextattr_args /* {
733 struct vnode *a_vp;
734 int a_attrnamespace;
735 const char *a_name;
736 struct uio *a_uio;
737 size_t *a_size;
738 kauth_cred_t a_cred;
739 struct proc *a_p;
740 } */ *ap = v;
741 struct vnode *vp = ap->a_vp;
742 struct inode *ip = VTOI(vp);
743 struct fs *fs = ip->i_fs;
744
745 if (fs->fs_magic == FS_UFS1_MAGIC) {
746 #ifdef UFS_EXTATTR
747 int error;
748
749 fstrans_start(vp->v_mount, FSTRANS_SHARED);
750 error = ufs_getextattr(ap);
751 fstrans_done(vp->v_mount);
752 return error;
753 #else
754 return (EOPNOTSUPP);
755 #endif
756 }
757
758 /* XXX Not implemented for UFS2 file systems. */
759 return (EOPNOTSUPP);
760 }
761
762 int
763 ffs_setextattr(void *v)
764 {
765 struct vop_setextattr_args /* {
766 struct vnode *a_vp;
767 int a_attrnamespace;
768 const char *a_name;
769 struct uio *a_uio;
770 kauth_cred_t a_cred;
771 struct proc *a_p;
772 } */ *ap = v;
773 struct vnode *vp = ap->a_vp;
774 struct inode *ip = VTOI(vp);
775 struct fs *fs = ip->i_fs;
776
777 if (fs->fs_magic == FS_UFS1_MAGIC) {
778 #ifdef UFS_EXTATTR
779 int error;
780
781 fstrans_start(vp->v_mount, FSTRANS_SHARED);
782 error = ufs_setextattr(ap);
783 fstrans_done(vp->v_mount);
784 return error;
785 #else
786 return (EOPNOTSUPP);
787 #endif
788 }
789
790 /* XXX Not implemented for UFS2 file systems. */
791 return (EOPNOTSUPP);
792 }
793
794 int
795 ffs_listextattr(void *v)
796 {
797 struct vop_listextattr_args /* {
798 struct vnode *a_vp;
799 int a_attrnamespace;
800 struct uio *a_uio;
801 size_t *a_size;
802 kauth_cred_t a_cred;
803 struct proc *a_p;
804 } */ *ap = v;
805 struct inode *ip = VTOI(ap->a_vp);
806 struct fs *fs = ip->i_fs;
807
808 /* Not supported for UFS1 file systems. */
809 if (fs->fs_magic == FS_UFS1_MAGIC)
810 return (EOPNOTSUPP);
811
812 /* XXX Not implemented for UFS2 file systems. */
813 return (EOPNOTSUPP);
814 }
815
816 int
817 ffs_deleteextattr(void *v)
818 {
819 struct vop_deleteextattr_args /* {
820 struct vnode *a_vp;
821 int a_attrnamespace;
822 kauth_cred_t a_cred;
823 struct proc *a_p;
824 } */ *ap = v;
825 struct vnode *vp = ap->a_vp;
826 struct inode *ip = VTOI(vp);
827 struct fs *fs = ip->i_fs;
828
829 if (fs->fs_magic == FS_UFS1_MAGIC) {
830 #ifdef UFS_EXTATTR
831 int error;
832
833 fstrans_start(vp->v_mount, FSTRANS_SHARED);
834 error = ufs_deleteextattr(ap);
835 fstrans_done(vp->v_mount);
836 return error;
837 #else
838 return (EOPNOTSUPP);
839 #endif
840 }
841
842 /* XXX Not implemented for UFS2 file systems. */
843 return (EOPNOTSUPP);
844 }
845
846 /*
847 * Lock the node.
848 */
849 int
850 ffs_lock(void *v)
851 {
852 struct vop_lock_args /* {
853 struct vnode *a_vp;
854 int a_flags;
855 } */ *ap = v;
856 struct vnode *vp = ap->a_vp;
857 struct mount *mp = vp->v_mount;
858 struct vnlock *lkp;
859 int flags = ap->a_flags;
860 int result;
861
862 if ((flags & LK_INTERLOCK) != 0) {
863 mutex_exit(&vp->v_interlock);
864 flags &= ~LK_INTERLOCK;
865 }
866
867 /*
868 * Fake lock during file system suspension.
869 */
870 if ((vp->v_type == VREG || vp->v_type == VDIR) &&
871 fstrans_is_owner(mp) &&
872 fstrans_getstate(mp) == FSTRANS_SUSPENDING) {
873 return 0;
874 }
875
876 for (;;) {
877 lkp = vp->v_vnlock;
878 result = vlockmgr(lkp, flags);
879 if (lkp == vp->v_vnlock || result != 0)
880 return result;
881 /*
882 * Apparent success, except that the vnode mutated between
883 * snapshot file vnode and regular file vnode while this
884 * thread slept. The lock currently held is not the right
885 * lock. Release it, and try to get the new lock.
886 */
887 (void) vlockmgr(lkp, LK_RELEASE);
888 }
889 }
890
891 /*
892 * Unlock the node.
893 */
894 int
895 ffs_unlock(void *v)
896 {
897 struct vop_unlock_args /* {
898 struct vnode *a_vp;
899 int a_flags;
900 } */ *ap = v;
901 struct vnode *vp = ap->a_vp;
902 struct mount *mp = vp->v_mount;
903
904 KASSERT(ap->a_flags == 0);
905
906 /*
907 * Fake unlock during file system suspension.
908 */
909 if ((vp->v_type == VREG || vp->v_type == VDIR) &&
910 fstrans_is_owner(mp) &&
911 fstrans_getstate(mp) == FSTRANS_SUSPENDING) {
912 return 0;
913 }
914 return (vlockmgr(vp->v_vnlock, LK_RELEASE));
915 }
916
917 /*
918 * Return whether or not the node is locked.
919 */
920 int
921 ffs_islocked(void *v)
922 {
923 struct vop_islocked_args /* {
924 struct vnode *a_vp;
925 } */ *ap = v;
926 struct vnode *vp = ap->a_vp;
927
928 return (vlockstatus(vp->v_vnlock));
929 }
930