1 | /* $NetBSD: ffs_vnops.c,v 1.125 2014/07/25 08:20:53 dholland Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2008, 2009 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, and by Andrew Doran. |
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.125 2014/07/25 08:20:53 dholland 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_fallocate_desc, genfs_eopnotsupp }, /* fallocate */ |
119 | { &vop_fdiscard_desc, genfs_eopnotsupp }, /* fdiscard */ |
120 | { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */ |
121 | { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ |
122 | { &vop_poll_desc, ufs_poll }, /* poll */ |
123 | { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ |
124 | { &vop_revoke_desc, ufs_revoke }, /* revoke */ |
125 | { &vop_mmap_desc, ufs_mmap }, /* mmap */ |
126 | { &vop_fsync_desc, ffs_fsync }, /* fsync */ |
127 | { &vop_seek_desc, ufs_seek }, /* seek */ |
128 | { &vop_remove_desc, ufs_remove }, /* remove */ |
129 | { &vop_link_desc, ufs_link }, /* link */ |
130 | { &vop_rename_desc, ufs_rename }, /* rename */ |
131 | { &vop_mkdir_desc, ufs_mkdir }, /* mkdir */ |
132 | { &vop_rmdir_desc, ufs_rmdir }, /* rmdir */ |
133 | { &vop_symlink_desc, ufs_symlink }, /* symlink */ |
134 | { &vop_readdir_desc, ufs_readdir }, /* readdir */ |
135 | { &vop_readlink_desc, ufs_readlink }, /* readlink */ |
136 | { &vop_abortop_desc, ufs_abortop }, /* abortop */ |
137 | { &vop_inactive_desc, ufs_inactive }, /* inactive */ |
138 | { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ |
139 | { &vop_lock_desc, ufs_lock }, /* lock */ |
140 | { &vop_unlock_desc, ufs_unlock }, /* unlock */ |
141 | { &vop_bmap_desc, ufs_bmap }, /* bmap */ |
142 | { &vop_strategy_desc, ufs_strategy }, /* strategy */ |
143 | { &vop_print_desc, ufs_print }, /* print */ |
144 | { &vop_islocked_desc, ufs_islocked }, /* islocked */ |
145 | { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */ |
146 | { &vop_advlock_desc, ufs_advlock }, /* advlock */ |
147 | { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ |
148 | { &vop_getpages_desc, genfs_getpages }, /* getpages */ |
149 | { &vop_putpages_desc, genfs_putpages }, /* putpages */ |
150 | { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ |
151 | { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ |
152 | { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ |
153 | { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ |
154 | { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ |
155 | { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ |
156 | { NULL, NULL } |
157 | }; |
158 | const struct vnodeopv_desc ffs_vnodeop_opv_desc = |
159 | { &ffs_vnodeop_p, ffs_vnodeop_entries }; |
160 | |
161 | int (**ffs_specop_p)(void *); |
162 | const struct vnodeopv_entry_desc ffs_specop_entries[] = { |
163 | { &vop_default_desc, vn_default_error }, |
164 | { &vop_lookup_desc, spec_lookup }, /* lookup */ |
165 | { &vop_create_desc, spec_create }, /* create */ |
166 | { &vop_mknod_desc, spec_mknod }, /* mknod */ |
167 | { &vop_open_desc, spec_open }, /* open */ |
168 | { &vop_close_desc, ufsspec_close }, /* close */ |
169 | { &vop_access_desc, ufs_access }, /* access */ |
170 | { &vop_getattr_desc, ufs_getattr }, /* getattr */ |
171 | { &vop_setattr_desc, ufs_setattr }, /* setattr */ |
172 | { &vop_read_desc, ufsspec_read }, /* read */ |
173 | { &vop_write_desc, ufsspec_write }, /* write */ |
174 | { &vop_fallocate_desc, spec_fallocate }, /* fallocate */ |
175 | { &vop_fdiscard_desc, spec_fdiscard }, /* fdiscard */ |
176 | { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ |
177 | { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ |
178 | { &vop_poll_desc, spec_poll }, /* poll */ |
179 | { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ |
180 | { &vop_revoke_desc, spec_revoke }, /* revoke */ |
181 | { &vop_mmap_desc, spec_mmap }, /* mmap */ |
182 | { &vop_fsync_desc, ffs_spec_fsync }, /* fsync */ |
183 | { &vop_seek_desc, spec_seek }, /* seek */ |
184 | { &vop_remove_desc, spec_remove }, /* remove */ |
185 | { &vop_link_desc, spec_link }, /* link */ |
186 | { &vop_rename_desc, spec_rename }, /* rename */ |
187 | { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ |
188 | { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ |
189 | { &vop_symlink_desc, spec_symlink }, /* symlink */ |
190 | { &vop_readdir_desc, spec_readdir }, /* readdir */ |
191 | { &vop_readlink_desc, spec_readlink }, /* readlink */ |
192 | { &vop_abortop_desc, spec_abortop }, /* abortop */ |
193 | { &vop_inactive_desc, ufs_inactive }, /* inactive */ |
194 | { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ |
195 | { &vop_lock_desc, ufs_lock }, /* lock */ |
196 | { &vop_unlock_desc, ufs_unlock }, /* unlock */ |
197 | { &vop_bmap_desc, spec_bmap }, /* bmap */ |
198 | { &vop_strategy_desc, spec_strategy }, /* strategy */ |
199 | { &vop_print_desc, ufs_print }, /* print */ |
200 | { &vop_islocked_desc, ufs_islocked }, /* islocked */ |
201 | { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ |
202 | { &vop_advlock_desc, spec_advlock }, /* advlock */ |
203 | { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ |
204 | { &vop_getpages_desc, spec_getpages }, /* getpages */ |
205 | { &vop_putpages_desc, spec_putpages }, /* putpages */ |
206 | { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ |
207 | { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ |
208 | { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ |
209 | { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ |
210 | { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ |
211 | { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ |
212 | { NULL, NULL } |
213 | }; |
214 | const struct vnodeopv_desc ffs_specop_opv_desc = |
215 | { &ffs_specop_p, ffs_specop_entries }; |
216 | |
217 | int (**ffs_fifoop_p)(void *); |
218 | const struct vnodeopv_entry_desc ffs_fifoop_entries[] = { |
219 | { &vop_default_desc, vn_default_error }, |
220 | { &vop_lookup_desc, vn_fifo_bypass }, /* lookup */ |
221 | { &vop_create_desc, vn_fifo_bypass }, /* create */ |
222 | { &vop_mknod_desc, vn_fifo_bypass }, /* mknod */ |
223 | { &vop_open_desc, vn_fifo_bypass }, /* open */ |
224 | { &vop_close_desc, ufsfifo_close }, /* close */ |
225 | { &vop_access_desc, ufs_access }, /* access */ |
226 | { &vop_getattr_desc, ufs_getattr }, /* getattr */ |
227 | { &vop_setattr_desc, ufs_setattr }, /* setattr */ |
228 | { &vop_read_desc, ufsfifo_read }, /* read */ |
229 | { &vop_write_desc, ufsfifo_write }, /* write */ |
230 | { &vop_fallocate_desc, vn_fifo_bypass }, /* fallocate */ |
231 | { &vop_fdiscard_desc, vn_fifo_bypass }, /* fdiscard */ |
232 | { &vop_ioctl_desc, vn_fifo_bypass }, /* ioctl */ |
233 | { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ |
234 | { &vop_poll_desc, vn_fifo_bypass }, /* poll */ |
235 | { &vop_kqfilter_desc, vn_fifo_bypass }, /* kqfilter */ |
236 | { &vop_revoke_desc, vn_fifo_bypass }, /* revoke */ |
237 | { &vop_mmap_desc, vn_fifo_bypass }, /* mmap */ |
238 | { &vop_fsync_desc, ffs_fsync }, /* fsync */ |
239 | { &vop_seek_desc, vn_fifo_bypass }, /* seek */ |
240 | { &vop_remove_desc, vn_fifo_bypass }, /* remove */ |
241 | { &vop_link_desc, vn_fifo_bypass }, /* link */ |
242 | { &vop_rename_desc, vn_fifo_bypass }, /* rename */ |
243 | { &vop_mkdir_desc, vn_fifo_bypass }, /* mkdir */ |
244 | { &vop_rmdir_desc, vn_fifo_bypass }, /* rmdir */ |
245 | { &vop_symlink_desc, vn_fifo_bypass }, /* symlink */ |
246 | { &vop_readdir_desc, vn_fifo_bypass }, /* readdir */ |
247 | { &vop_readlink_desc, vn_fifo_bypass }, /* readlink */ |
248 | { &vop_abortop_desc, vn_fifo_bypass }, /* abortop */ |
249 | { &vop_inactive_desc, ufs_inactive }, /* inactive */ |
250 | { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ |
251 | { &vop_lock_desc, ufs_lock }, /* lock */ |
252 | { &vop_unlock_desc, ufs_unlock }, /* unlock */ |
253 | { &vop_bmap_desc, vn_fifo_bypass }, /* bmap */ |
254 | { &vop_strategy_desc, vn_fifo_bypass }, /* strategy */ |
255 | { &vop_print_desc, ufs_print }, /* print */ |
256 | { &vop_islocked_desc, ufs_islocked }, /* islocked */ |
257 | { &vop_pathconf_desc, vn_fifo_bypass }, /* pathconf */ |
258 | { &vop_advlock_desc, vn_fifo_bypass }, /* advlock */ |
259 | { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ |
260 | { &vop_putpages_desc, vn_fifo_bypass }, /* putpages */ |
261 | { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ |
262 | { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ |
263 | { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ |
264 | { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ |
265 | { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ |
266 | { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ |
267 | { NULL, NULL } |
268 | }; |
269 | const struct vnodeopv_desc ffs_fifoop_opv_desc = |
270 | { &ffs_fifoop_p, ffs_fifoop_entries }; |
271 | |
272 | #include <ufs/ufs/ufs_readwrite.c> |
273 | |
274 | int |
275 | ffs_spec_fsync(void *v) |
276 | { |
277 | struct vop_fsync_args /* { |
278 | struct vnode *a_vp; |
279 | kauth_cred_t a_cred; |
280 | int a_flags; |
281 | off_t a_offlo; |
282 | off_t a_offhi; |
283 | struct lwp *a_l; |
284 | } */ *ap = v; |
285 | int error, flags, uflags; |
286 | struct vnode *vp; |
287 | struct mount *mp; |
288 | |
289 | flags = ap->a_flags; |
290 | uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0); |
291 | vp = ap->a_vp; |
292 | mp = vp->v_mount; |
293 | |
294 | fstrans_start(mp, FSTRANS_LAZY); |
295 | |
296 | error = spec_fsync(v); |
297 | if (error) |
298 | goto out; |
299 | |
300 | #ifdef WAPBL |
301 | if (mp && mp->mnt_wapbl) { |
302 | /* |
303 | * Don't bother writing out metadata if the syncer is |
304 | * making the request. We will let the sync vnode |
305 | * write it out in a single burst through a call to |
306 | * VFS_SYNC(). |
307 | */ |
308 | if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) |
309 | goto out; |
310 | if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE |
311 | | IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) { |
312 | error = UFS_WAPBL_BEGIN(mp); |
313 | if (error != 0) |
314 | goto out; |
315 | error = ffs_update(vp, NULL, NULL, uflags); |
316 | UFS_WAPBL_END(mp); |
317 | } |
318 | goto out; |
319 | } |
320 | #endif /* WAPBL */ |
321 | |
322 | error = ffs_update(vp, NULL, NULL, uflags); |
323 | |
324 | out: |
325 | fstrans_done(mp); |
326 | return error; |
327 | } |
328 | |
329 | int |
330 | ffs_fsync(void *v) |
331 | { |
332 | struct vop_fsync_args /* { |
333 | struct vnode *a_vp; |
334 | kauth_cred_t a_cred; |
335 | int a_flags; |
336 | off_t a_offlo; |
337 | off_t a_offhi; |
338 | struct lwp *a_l; |
339 | } */ *ap = v; |
340 | struct buf *bp; |
341 | int num, error, i; |
342 | struct indir ia[UFS_NIADDR + 1]; |
343 | int bsize; |
344 | daddr_t blk_high; |
345 | struct vnode *vp; |
346 | struct mount *mp; |
347 | |
348 | vp = ap->a_vp; |
349 | mp = vp->v_mount; |
350 | |
351 | fstrans_start(mp, FSTRANS_LAZY); |
352 | if ((ap->a_offlo == 0 && ap->a_offhi == 0) || (vp->v_type != VREG)) { |
353 | error = ffs_full_fsync(vp, ap->a_flags); |
354 | goto out; |
355 | } |
356 | |
357 | bsize = mp->mnt_stat.f_iosize; |
358 | blk_high = ap->a_offhi / bsize; |
359 | if (ap->a_offhi % bsize != 0) |
360 | blk_high++; |
361 | |
362 | /* |
363 | * First, flush all pages in range. |
364 | */ |
365 | |
366 | mutex_enter(vp->v_interlock); |
367 | error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo), |
368 | round_page(ap->a_offhi), PGO_CLEANIT | |
369 | ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0)); |
370 | if (error) { |
371 | goto out; |
372 | } |
373 | |
374 | #ifdef WAPBL |
375 | KASSERT(vp->v_type == VREG); |
376 | if (mp->mnt_wapbl) { |
377 | /* |
378 | * Don't bother writing out metadata if the syncer is |
379 | * making the request. We will let the sync vnode |
380 | * write it out in a single burst through a call to |
381 | * VFS_SYNC(). |
382 | */ |
383 | if ((ap->a_flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) { |
384 | fstrans_done(mp); |
385 | return 0; |
386 | } |
387 | error = 0; |
388 | if (vp->v_tag == VT_UFS && VTOI(vp)->i_flag & |
389 | (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY | |
390 | IN_MODIFIED | IN_ACCESSED)) { |
391 | error = UFS_WAPBL_BEGIN(mp); |
392 | if (error) { |
393 | fstrans_done(mp); |
394 | return error; |
395 | } |
396 | error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | |
397 | ((ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0)); |
398 | UFS_WAPBL_END(mp); |
399 | } |
400 | if (error || (ap->a_flags & FSYNC_NOLOG) != 0) { |
401 | fstrans_done(mp); |
402 | return error; |
403 | } |
404 | error = wapbl_flush(mp->mnt_wapbl, 0); |
405 | fstrans_done(mp); |
406 | return error; |
407 | } |
408 | #endif /* WAPBL */ |
409 | |
410 | /* |
411 | * Then, flush indirect blocks. |
412 | */ |
413 | |
414 | if (blk_high >= UFS_NDADDR) { |
415 | error = ufs_getlbns(vp, blk_high, ia, &num); |
416 | if (error) |
417 | goto out; |
418 | |
419 | mutex_enter(&bufcache_lock); |
420 | for (i = 0; i < num; i++) { |
421 | if ((bp = incore(vp, ia[i].in_lbn)) == NULL) |
422 | continue; |
423 | if ((bp->b_cflags & BC_BUSY) != 0 || |
424 | (bp->b_oflags & BO_DELWRI) == 0) |
425 | continue; |
426 | bp->b_cflags |= BC_BUSY | BC_VFLUSH; |
427 | mutex_exit(&bufcache_lock); |
428 | bawrite(bp); |
429 | mutex_enter(&bufcache_lock); |
430 | } |
431 | mutex_exit(&bufcache_lock); |
432 | } |
433 | |
434 | if (ap->a_flags & FSYNC_WAIT) { |
435 | mutex_enter(vp->v_interlock); |
436 | while (vp->v_numoutput > 0) |
437 | cv_wait(&vp->v_cv, vp->v_interlock); |
438 | mutex_exit(vp->v_interlock); |
439 | } |
440 | |
441 | error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | |
442 | (((ap->a_flags & (FSYNC_WAIT | FSYNC_DATAONLY)) == FSYNC_WAIT) |
443 | ? UPDATE_WAIT : 0)); |
444 | |
445 | if (error == 0 && ap->a_flags & FSYNC_CACHE) { |
446 | int l = 0; |
447 | VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE, |
448 | curlwp->l_cred); |
449 | } |
450 | |
451 | out: |
452 | fstrans_done(mp); |
453 | return error; |
454 | } |
455 | |
456 | /* |
457 | * Synch an open file. Called for VOP_FSYNC(). |
458 | */ |
459 | /* ARGSUSED */ |
460 | int |
461 | ffs_full_fsync(struct vnode *vp, int flags) |
462 | { |
463 | int error, i, uflags; |
464 | |
465 | KASSERT(vp->v_tag == VT_UFS); |
466 | KASSERT(VTOI(vp) != NULL); |
467 | KASSERT(vp->v_type != VCHR && vp->v_type != VBLK); |
468 | |
469 | uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0); |
470 | |
471 | #ifdef WAPBL |
472 | struct mount *mp = vp->v_mount; |
473 | if (mp && mp->mnt_wapbl) { |
474 | |
475 | /* |
476 | * Flush all dirty data associated with the vnode. |
477 | */ |
478 | if (vp->v_type == VREG) { |
479 | int pflags = PGO_ALLPAGES | PGO_CLEANIT; |
480 | |
481 | if ((flags & FSYNC_LAZY)) |
482 | pflags |= PGO_LAZY; |
483 | if ((flags & FSYNC_WAIT)) |
484 | pflags |= PGO_SYNCIO; |
485 | if (fstrans_getstate(mp) == FSTRANS_SUSPENDING) |
486 | pflags |= PGO_FREE; |
487 | mutex_enter(vp->v_interlock); |
488 | error = VOP_PUTPAGES(vp, 0, 0, pflags); |
489 | if (error) |
490 | return error; |
491 | } |
492 | |
493 | /* |
494 | * Don't bother writing out metadata if the syncer is |
495 | * making the request. We will let the sync vnode |
496 | * write it out in a single burst through a call to |
497 | * VFS_SYNC(). |
498 | */ |
499 | if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) |
500 | return 0; |
501 | |
502 | if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE |
503 | | IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) { |
504 | error = UFS_WAPBL_BEGIN(mp); |
505 | if (error) |
506 | return error; |
507 | error = ffs_update(vp, NULL, NULL, uflags); |
508 | UFS_WAPBL_END(mp); |
509 | } else { |
510 | error = 0; |
511 | } |
512 | if (error || (flags & FSYNC_NOLOG) != 0) |
513 | return error; |
514 | |
515 | /* |
516 | * Don't flush the log if the vnode being flushed |
517 | * contains no dirty buffers that could be in the log. |
518 | */ |
519 | if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { |
520 | error = wapbl_flush(mp->mnt_wapbl, 0); |
521 | if (error) |
522 | return error; |
523 | } |
524 | |
525 | if ((flags & FSYNC_WAIT) != 0) { |
526 | mutex_enter(vp->v_interlock); |
527 | while (vp->v_numoutput != 0) |
528 | cv_wait(&vp->v_cv, vp->v_interlock); |
529 | mutex_exit(vp->v_interlock); |
530 | } |
531 | |
532 | return error; |
533 | } |
534 | #endif /* WAPBL */ |
535 | |
536 | error = vflushbuf(vp, flags); |
537 | if (error == 0) |
538 | error = ffs_update(vp, NULL, NULL, uflags); |
539 | if (error == 0 && (flags & FSYNC_CACHE) != 0) { |
540 | i = 1; |
541 | (void)VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE, |
542 | kauth_cred_get()); |
543 | } |
544 | |
545 | return error; |
546 | } |
547 | |
548 | /* |
549 | * Reclaim an inode so that it can be used for other purposes. |
550 | */ |
551 | int |
552 | ffs_reclaim(void *v) |
553 | { |
554 | struct vop_reclaim_args /* { |
555 | struct vnode *a_vp; |
556 | struct lwp *a_l; |
557 | } */ *ap = v; |
558 | struct vnode *vp = ap->a_vp; |
559 | struct inode *ip = VTOI(vp); |
560 | struct mount *mp = vp->v_mount; |
561 | struct ufsmount *ump = ip->i_ump; |
562 | void *data; |
563 | int error; |
564 | |
565 | fstrans_start(mp, FSTRANS_LAZY); |
566 | /* |
567 | * The inode must be freed and updated before being removed |
568 | * from its hash chain. Other threads trying to gain a hold |
569 | * or lock on the inode will be stalled. |
570 | */ |
571 | error = UFS_WAPBL_BEGIN(mp); |
572 | if (error) { |
573 | fstrans_done(mp); |
574 | return error; |
575 | } |
576 | if (ip->i_nlink <= 0 && ip->i_omode != 0 && |
577 | (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) |
578 | ffs_vfree(vp, ip->i_number, ip->i_omode); |
579 | UFS_WAPBL_END(mp); |
580 | if ((error = ufs_reclaim(vp)) != 0) { |
581 | fstrans_done(mp); |
582 | return (error); |
583 | } |
584 | if (ip->i_din.ffs1_din != NULL) { |
585 | if (ump->um_fstype == UFS1) |
586 | pool_cache_put(ffs_dinode1_cache, ip->i_din.ffs1_din); |
587 | else |
588 | pool_cache_put(ffs_dinode2_cache, ip->i_din.ffs2_din); |
589 | } |
590 | /* |
591 | * To interlock with ffs_sync(). |
592 | */ |
593 | genfs_node_destroy(vp); |
594 | mutex_enter(vp->v_interlock); |
595 | data = vp->v_data; |
596 | vp->v_data = NULL; |
597 | mutex_exit(vp->v_interlock); |
598 | |
599 | /* |
600 | * XXX MFS ends up here, too, to free an inode. Should we create |
601 | * XXX a separate pool for MFS inodes? |
602 | */ |
603 | pool_cache_put(ffs_inode_cache, data); |
604 | fstrans_done(mp); |
605 | return (0); |
606 | } |
607 | |
608 | /* |
609 | * Return the last logical file offset that should be written for this file |
610 | * if we're doing a write that ends at "size". |
611 | */ |
612 | |
613 | void |
614 | ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags) |
615 | { |
616 | struct inode *ip = VTOI(vp); |
617 | struct fs *fs = ip->i_fs; |
618 | daddr_t olbn, nlbn; |
619 | |
620 | olbn = ffs_lblkno(fs, ip->i_size); |
621 | nlbn = ffs_lblkno(fs, size); |
622 | if (nlbn < UFS_NDADDR && olbn <= nlbn) { |
623 | *eobp = ffs_fragroundup(fs, size); |
624 | } else { |
625 | *eobp = ffs_blkroundup(fs, size); |
626 | } |
627 | } |
628 | |
629 | int |
630 | ffs_openextattr(void *v) |
631 | { |
632 | struct vop_openextattr_args /* { |
633 | struct vnode *a_vp; |
634 | kauth_cred_t a_cred; |
635 | struct proc *a_p; |
636 | } */ *ap = v; |
637 | struct inode *ip = VTOI(ap->a_vp); |
638 | struct fs *fs = ip->i_fs; |
639 | |
640 | /* Not supported for UFS1 file systems. */ |
641 | if (fs->fs_magic == FS_UFS1_MAGIC) |
642 | return (EOPNOTSUPP); |
643 | |
644 | /* XXX Not implemented for UFS2 file systems. */ |
645 | return (EOPNOTSUPP); |
646 | } |
647 | |
648 | int |
649 | ffs_closeextattr(void *v) |
650 | { |
651 | struct vop_closeextattr_args /* { |
652 | struct vnode *a_vp; |
653 | int a_commit; |
654 | kauth_cred_t a_cred; |
655 | struct proc *a_p; |
656 | } */ *ap = v; |
657 | struct inode *ip = VTOI(ap->a_vp); |
658 | struct fs *fs = ip->i_fs; |
659 | |
660 | /* Not supported for UFS1 file systems. */ |
661 | if (fs->fs_magic == FS_UFS1_MAGIC) |
662 | return (EOPNOTSUPP); |
663 | |
664 | /* XXX Not implemented for UFS2 file systems. */ |
665 | return (EOPNOTSUPP); |
666 | } |
667 | |
668 | int |
669 | ffs_getextattr(void *v) |
670 | { |
671 | struct vop_getextattr_args /* { |
672 | struct vnode *a_vp; |
673 | int a_attrnamespace; |
674 | const char *a_name; |
675 | struct uio *a_uio; |
676 | size_t *a_size; |
677 | kauth_cred_t a_cred; |
678 | struct proc *a_p; |
679 | } */ *ap = v; |
680 | struct vnode *vp = ap->a_vp; |
681 | struct inode *ip = VTOI(vp); |
682 | struct fs *fs = ip->i_fs; |
683 | |
684 | if (fs->fs_magic == FS_UFS1_MAGIC) { |
685 | #ifdef UFS_EXTATTR |
686 | int error; |
687 | |
688 | fstrans_start(vp->v_mount, FSTRANS_SHARED); |
689 | error = ufs_getextattr(ap); |
690 | fstrans_done(vp->v_mount); |
691 | return error; |
692 | #else |
693 | return (EOPNOTSUPP); |
694 | #endif |
695 | } |
696 | |
697 | /* XXX Not implemented for UFS2 file systems. */ |
698 | return (EOPNOTSUPP); |
699 | } |
700 | |
701 | int |
702 | ffs_setextattr(void *v) |
703 | { |
704 | struct vop_setextattr_args /* { |
705 | struct vnode *a_vp; |
706 | int a_attrnamespace; |
707 | const char *a_name; |
708 | struct uio *a_uio; |
709 | kauth_cred_t a_cred; |
710 | struct proc *a_p; |
711 | } */ *ap = v; |
712 | struct vnode *vp = ap->a_vp; |
713 | struct inode *ip = VTOI(vp); |
714 | struct fs *fs = ip->i_fs; |
715 | |
716 | if (fs->fs_magic == FS_UFS1_MAGIC) { |
717 | #ifdef UFS_EXTATTR |
718 | int error; |
719 | |
720 | fstrans_start(vp->v_mount, FSTRANS_SHARED); |
721 | error = ufs_setextattr(ap); |
722 | fstrans_done(vp->v_mount); |
723 | return error; |
724 | #else |
725 | return (EOPNOTSUPP); |
726 | #endif |
727 | } |
728 | |
729 | /* XXX Not implemented for UFS2 file systems. */ |
730 | return (EOPNOTSUPP); |
731 | } |
732 | |
733 | int |
734 | ffs_listextattr(void *v) |
735 | { |
736 | struct vop_listextattr_args /* { |
737 | struct vnode *a_vp; |
738 | int a_attrnamespace; |
739 | struct uio *a_uio; |
740 | size_t *a_size; |
741 | kauth_cred_t a_cred; |
742 | struct proc *a_p; |
743 | } */ *ap = v; |
744 | struct inode *ip = VTOI(ap->a_vp); |
745 | struct fs *fs = ip->i_fs; |
746 | |
747 | if (fs->fs_magic == FS_UFS1_MAGIC) { |
748 | #ifdef UFS_EXTATTR |
749 | struct vnode *vp = ap->a_vp; |
750 | int error; |
751 | |
752 | fstrans_start(vp->v_mount, FSTRANS_SHARED); |
753 | error = ufs_listextattr(ap); |
754 | fstrans_done(vp->v_mount); |
755 | return error; |
756 | #else |
757 | return (EOPNOTSUPP); |
758 | #endif |
759 | } |
760 | |
761 | /* XXX Not implemented for UFS2 file systems. */ |
762 | return (EOPNOTSUPP); |
763 | } |
764 | |
765 | int |
766 | ffs_deleteextattr(void *v) |
767 | { |
768 | struct vop_deleteextattr_args /* { |
769 | struct vnode *a_vp; |
770 | int a_attrnamespace; |
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_deleteextattr(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 | |