xref: /netbsd-src/sys/ufs/ffs/ffs_vnops.c (revision 86811edb37e43f44504b192591c863c5d48f5e08)
1 /*	$NetBSD: ffs_vnops.c,v 1.77 2005/12/11 12:25:25 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1982, 1986, 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  *	@(#)ffs_vnops.c	8.15 (Berkeley) 5/14/95
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.77 2005/12/11 12:25:25 christos Exp $");
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/resourcevar.h>
40 #include <sys/kernel.h>
41 #include <sys/file.h>
42 #include <sys/stat.h>
43 #include <sys/buf.h>
44 #include <sys/event.h>
45 #include <sys/proc.h>
46 #include <sys/mount.h>
47 #include <sys/vnode.h>
48 #include <sys/pool.h>
49 #include <sys/signalvar.h>
50 
51 #include <miscfs/fifofs/fifo.h>
52 #include <miscfs/genfs/genfs.h>
53 #include <miscfs/specfs/specdev.h>
54 
55 #include <ufs/ufs/inode.h>
56 #include <ufs/ufs/dir.h>
57 #include <ufs/ufs/ufs_extern.h>
58 #include <ufs/ufs/ufsmount.h>
59 
60 #include <ufs/ffs/fs.h>
61 #include <ufs/ffs/ffs_extern.h>
62 
63 #include <uvm/uvm.h>
64 
65 static int ffs_full_fsync(void *);
66 
67 /* Global vfs data structures for ufs. */
68 int (**ffs_vnodeop_p)(void *);
69 const struct vnodeopv_entry_desc ffs_vnodeop_entries[] = {
70 	{ &vop_default_desc, vn_default_error },
71 	{ &vop_lookup_desc, ufs_lookup },		/* lookup */
72 	{ &vop_create_desc, ufs_create },		/* create */
73 	{ &vop_whiteout_desc, ufs_whiteout },		/* whiteout */
74 	{ &vop_mknod_desc, ufs_mknod },			/* mknod */
75 	{ &vop_open_desc, ufs_open },			/* open */
76 	{ &vop_close_desc, ufs_close },			/* close */
77 	{ &vop_access_desc, ufs_access },		/* access */
78 	{ &vop_getattr_desc, ufs_getattr },		/* getattr */
79 	{ &vop_setattr_desc, ufs_setattr },		/* setattr */
80 	{ &vop_read_desc, ffs_read },			/* read */
81 	{ &vop_write_desc, ffs_write },			/* write */
82 	{ &vop_lease_desc, ufs_lease_check },		/* lease */
83 	{ &vop_ioctl_desc, ufs_ioctl },			/* ioctl */
84 	{ &vop_fcntl_desc, ufs_fcntl },			/* fcntl */
85 	{ &vop_poll_desc, ufs_poll },			/* poll */
86 	{ &vop_kqfilter_desc, genfs_kqfilter },		/* kqfilter */
87 	{ &vop_revoke_desc, ufs_revoke },		/* revoke */
88 	{ &vop_mmap_desc, ufs_mmap },			/* mmap */
89 	{ &vop_fsync_desc, ffs_fsync },			/* fsync */
90 	{ &vop_seek_desc, ufs_seek },			/* seek */
91 	{ &vop_remove_desc, ufs_remove },		/* remove */
92 	{ &vop_link_desc, ufs_link },			/* link */
93 	{ &vop_rename_desc, ufs_rename },		/* rename */
94 	{ &vop_mkdir_desc, ufs_mkdir },			/* mkdir */
95 	{ &vop_rmdir_desc, ufs_rmdir },			/* rmdir */
96 	{ &vop_symlink_desc, ufs_symlink },		/* symlink */
97 	{ &vop_readdir_desc, ufs_readdir },		/* readdir */
98 	{ &vop_readlink_desc, ufs_readlink },		/* readlink */
99 	{ &vop_abortop_desc, ufs_abortop },		/* abortop */
100 	{ &vop_inactive_desc, ufs_inactive },		/* inactive */
101 	{ &vop_reclaim_desc, ffs_reclaim },		/* reclaim */
102 	{ &vop_lock_desc, ufs_lock },			/* lock */
103 	{ &vop_unlock_desc, ufs_unlock },		/* unlock */
104 	{ &vop_bmap_desc, ufs_bmap },			/* bmap */
105 	{ &vop_strategy_desc, ufs_strategy },		/* strategy */
106 	{ &vop_print_desc, ufs_print },			/* print */
107 	{ &vop_islocked_desc, ufs_islocked },		/* islocked */
108 	{ &vop_pathconf_desc, ufs_pathconf },		/* pathconf */
109 	{ &vop_advlock_desc, ufs_advlock },		/* advlock */
110 	{ &vop_bwrite_desc, vn_bwrite },		/* bwrite */
111 	{ &vop_getpages_desc, ffs_getpages },		/* getpages */
112 	{ &vop_putpages_desc, genfs_putpages },		/* putpages */
113 	{ &vop_openextattr_desc, ffs_openextattr },	/* openextattr */
114 	{ &vop_closeextattr_desc, ffs_closeextattr },	/* closeextattr */
115 	{ &vop_getextattr_desc, ffs_getextattr },	/* getextattr */
116 	{ &vop_setextattr_desc, ffs_setextattr },	/* setextattr */
117 	{ &vop_listextattr_desc, ffs_listextattr },	/* listextattr */
118 	{ &vop_deleteextattr_desc, ffs_deleteextattr },	/* deleteextattr */
119 	{ NULL, NULL }
120 };
121 const struct vnodeopv_desc ffs_vnodeop_opv_desc =
122 	{ &ffs_vnodeop_p, ffs_vnodeop_entries };
123 
124 int (**ffs_specop_p)(void *);
125 const struct vnodeopv_entry_desc ffs_specop_entries[] = {
126 	{ &vop_default_desc, vn_default_error },
127 	{ &vop_lookup_desc, spec_lookup },		/* lookup */
128 	{ &vop_create_desc, spec_create },		/* create */
129 	{ &vop_mknod_desc, spec_mknod },		/* mknod */
130 	{ &vop_open_desc, spec_open },			/* open */
131 	{ &vop_close_desc, ufsspec_close },		/* close */
132 	{ &vop_access_desc, ufs_access },		/* access */
133 	{ &vop_getattr_desc, ufs_getattr },		/* getattr */
134 	{ &vop_setattr_desc, ufs_setattr },		/* setattr */
135 	{ &vop_read_desc, ufsspec_read },		/* read */
136 	{ &vop_write_desc, ufsspec_write },		/* write */
137 	{ &vop_lease_desc, spec_lease_check },		/* lease */
138 	{ &vop_ioctl_desc, spec_ioctl },		/* ioctl */
139 	{ &vop_fcntl_desc, ufs_fcntl },			/* fcntl */
140 	{ &vop_poll_desc, spec_poll },			/* poll */
141 	{ &vop_kqfilter_desc, spec_kqfilter },		/* kqfilter */
142 	{ &vop_revoke_desc, spec_revoke },		/* revoke */
143 	{ &vop_mmap_desc, spec_mmap },			/* mmap */
144 	{ &vop_fsync_desc, ffs_fsync },			/* fsync */
145 	{ &vop_seek_desc, spec_seek },			/* seek */
146 	{ &vop_remove_desc, spec_remove },		/* remove */
147 	{ &vop_link_desc, spec_link },			/* link */
148 	{ &vop_rename_desc, spec_rename },		/* rename */
149 	{ &vop_mkdir_desc, spec_mkdir },		/* mkdir */
150 	{ &vop_rmdir_desc, spec_rmdir },		/* rmdir */
151 	{ &vop_symlink_desc, spec_symlink },		/* symlink */
152 	{ &vop_readdir_desc, spec_readdir },		/* readdir */
153 	{ &vop_readlink_desc, spec_readlink },		/* readlink */
154 	{ &vop_abortop_desc, spec_abortop },		/* abortop */
155 	{ &vop_inactive_desc, ufs_inactive },		/* inactive */
156 	{ &vop_reclaim_desc, ffs_reclaim },		/* reclaim */
157 	{ &vop_lock_desc, ufs_lock },			/* lock */
158 	{ &vop_unlock_desc, ufs_unlock },		/* unlock */
159 	{ &vop_bmap_desc, spec_bmap },			/* bmap */
160 	{ &vop_strategy_desc, spec_strategy },		/* strategy */
161 	{ &vop_print_desc, ufs_print },			/* print */
162 	{ &vop_islocked_desc, ufs_islocked },		/* islocked */
163 	{ &vop_pathconf_desc, spec_pathconf },		/* pathconf */
164 	{ &vop_advlock_desc, spec_advlock },		/* advlock */
165 	{ &vop_bwrite_desc, vn_bwrite },		/* bwrite */
166 	{ &vop_getpages_desc, spec_getpages },		/* getpages */
167 	{ &vop_putpages_desc, spec_putpages },		/* putpages */
168 	{ &vop_openextattr_desc, ffs_openextattr },	/* openextattr */
169 	{ &vop_closeextattr_desc, ffs_closeextattr },	/* closeextattr */
170 	{ &vop_getextattr_desc, ffs_getextattr },	/* getextattr */
171 	{ &vop_setextattr_desc, ffs_setextattr },	/* setextattr */
172 	{ &vop_listextattr_desc, ffs_listextattr },	/* listextattr */
173 	{ &vop_deleteextattr_desc, ffs_deleteextattr },	/* deleteextattr */
174 	{ NULL, NULL }
175 };
176 const struct vnodeopv_desc ffs_specop_opv_desc =
177 	{ &ffs_specop_p, ffs_specop_entries };
178 
179 int (**ffs_fifoop_p)(void *);
180 const struct vnodeopv_entry_desc ffs_fifoop_entries[] = {
181 	{ &vop_default_desc, vn_default_error },
182 	{ &vop_lookup_desc, fifo_lookup },		/* lookup */
183 	{ &vop_create_desc, fifo_create },		/* create */
184 	{ &vop_mknod_desc, fifo_mknod },		/* mknod */
185 	{ &vop_open_desc, fifo_open },			/* open */
186 	{ &vop_close_desc, ufsfifo_close },		/* close */
187 	{ &vop_access_desc, ufs_access },		/* access */
188 	{ &vop_getattr_desc, ufs_getattr },		/* getattr */
189 	{ &vop_setattr_desc, ufs_setattr },		/* setattr */
190 	{ &vop_read_desc, ufsfifo_read },		/* read */
191 	{ &vop_write_desc, ufsfifo_write },		/* write */
192 	{ &vop_lease_desc, fifo_lease_check },		/* lease */
193 	{ &vop_ioctl_desc, fifo_ioctl },		/* ioctl */
194 	{ &vop_fcntl_desc, ufs_fcntl },			/* fcntl */
195 	{ &vop_poll_desc, fifo_poll },			/* poll */
196 	{ &vop_kqfilter_desc, fifo_kqfilter },		/* kqfilter */
197 	{ &vop_revoke_desc, fifo_revoke },		/* revoke */
198 	{ &vop_mmap_desc, fifo_mmap },			/* mmap */
199 	{ &vop_fsync_desc, ffs_fsync },			/* fsync */
200 	{ &vop_seek_desc, fifo_seek },			/* seek */
201 	{ &vop_remove_desc, fifo_remove },		/* remove */
202 	{ &vop_link_desc, fifo_link },			/* link */
203 	{ &vop_rename_desc, fifo_rename },		/* rename */
204 	{ &vop_mkdir_desc, fifo_mkdir },		/* mkdir */
205 	{ &vop_rmdir_desc, fifo_rmdir },		/* rmdir */
206 	{ &vop_symlink_desc, fifo_symlink },		/* symlink */
207 	{ &vop_readdir_desc, fifo_readdir },		/* readdir */
208 	{ &vop_readlink_desc, fifo_readlink },		/* readlink */
209 	{ &vop_abortop_desc, fifo_abortop },		/* abortop */
210 	{ &vop_inactive_desc, ufs_inactive },		/* inactive */
211 	{ &vop_reclaim_desc, ffs_reclaim },		/* reclaim */
212 	{ &vop_lock_desc, ufs_lock },			/* lock */
213 	{ &vop_unlock_desc, ufs_unlock },		/* unlock */
214 	{ &vop_bmap_desc, fifo_bmap },			/* bmap */
215 	{ &vop_strategy_desc, fifo_strategy },		/* strategy */
216 	{ &vop_print_desc, ufs_print },			/* print */
217 	{ &vop_islocked_desc, ufs_islocked },		/* islocked */
218 	{ &vop_pathconf_desc, fifo_pathconf },		/* pathconf */
219 	{ &vop_advlock_desc, fifo_advlock },		/* advlock */
220 	{ &vop_bwrite_desc, vn_bwrite },		/* bwrite */
221 	{ &vop_putpages_desc, fifo_putpages }, 		/* putpages */
222 	{ &vop_openextattr_desc, ffs_openextattr },	/* openextattr */
223 	{ &vop_closeextattr_desc, ffs_closeextattr },	/* closeextattr */
224 	{ &vop_getextattr_desc, ffs_getextattr },	/* getextattr */
225 	{ &vop_setextattr_desc, ffs_setextattr },	/* setextattr */
226 	{ &vop_listextattr_desc, ffs_listextattr },	/* listextattr */
227 	{ &vop_deleteextattr_desc, ffs_deleteextattr },	/* deleteextattr */
228 	{ NULL, NULL }
229 };
230 const struct vnodeopv_desc ffs_fifoop_opv_desc =
231 	{ &ffs_fifoop_p, ffs_fifoop_entries };
232 
233 #include <ufs/ufs/ufs_readwrite.c>
234 
235 int
236 ffs_fsync(void *v)
237 {
238 	struct vop_fsync_args /* {
239 		struct vnode *a_vp;
240 		struct ucred *a_cred;
241 		int a_flags;
242 		off_t a_offlo;
243 		off_t a_offhi;
244 		struct lwp *a_l;
245 	} */ *ap = v;
246 	struct buf *bp;
247 	int s, num, error, i;
248 	struct indir ia[NIADDR + 1];
249 	int bsize;
250 	daddr_t blk_high;
251 	struct vnode *vp;
252 
253 	/*
254 	 * XXX no easy way to sync a range in a file with softdep.
255 	 */
256 	if ((ap->a_offlo == 0 && ap->a_offhi == 0) || DOINGSOFTDEP(ap->a_vp) ||
257 			(ap->a_vp->v_type != VREG))
258 		return ffs_full_fsync(v);
259 
260 	vp = ap->a_vp;
261 
262 	bsize = ap->a_vp->v_mount->mnt_stat.f_iosize;
263 	blk_high = ap->a_offhi / bsize;
264 	if (ap->a_offhi % bsize != 0)
265 		blk_high++;
266 
267 	/*
268 	 * First, flush all pages in range.
269 	 */
270 
271 	simple_lock(&vp->v_interlock);
272 	error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo),
273 	    round_page(ap->a_offhi), PGO_CLEANIT |
274 	    ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0));
275 	if (error) {
276 		return error;
277 	}
278 
279 	/*
280 	 * Then, flush indirect blocks.
281 	 */
282 
283 	s = splbio();
284 	if (blk_high >= NDADDR) {
285 		error = ufs_getlbns(vp, blk_high, ia, &num);
286 		if (error) {
287 			splx(s);
288 			return error;
289 		}
290 		for (i = 0; i < num; i++) {
291 			bp = incore(vp, ia[i].in_lbn);
292 			if (bp != NULL) {
293 				simple_lock(&bp->b_interlock);
294 				if (!(bp->b_flags & B_BUSY) && (bp->b_flags & B_DELWRI)) {
295 					bp->b_flags |= B_BUSY | B_VFLUSH;
296 					simple_unlock(&bp->b_interlock);
297 					splx(s);
298 					bawrite(bp);
299 					s = splbio();
300 				} else {
301 					simple_unlock(&bp->b_interlock);
302 				}
303 			}
304 		}
305 	}
306 
307 	if (ap->a_flags & FSYNC_WAIT) {
308 		simple_lock(&global_v_numoutput_slock);
309 		while (vp->v_numoutput > 0) {
310 			vp->v_flag |= VBWAIT;
311 			ltsleep(&vp->v_numoutput, PRIBIO + 1, "fsync_range", 0,
312 				&global_v_numoutput_slock);
313 		}
314 		simple_unlock(&global_v_numoutput_slock);
315 	}
316 	splx(s);
317 
318 	error = ffs_update(vp, NULL, NULL,
319 	    ((ap->a_flags & (FSYNC_WAIT | FSYNC_DATAONLY)) == FSYNC_WAIT)
320 	    ? UPDATE_WAIT : 0);
321 
322 	if (error == 0 && ap->a_flags & FSYNC_CACHE) {
323 		int l = 0;
324 		VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE,
325 			ap->a_l->l_proc->p_ucred, ap->a_l);
326 	}
327 
328 	return error;
329 }
330 
331 /*
332  * Synch an open file.
333  */
334 /* ARGSUSED */
335 static int
336 ffs_full_fsync(void *v)
337 {
338 	struct vop_fsync_args /* {
339 		struct vnode *a_vp;
340 		struct ucred *a_cred;
341 		int a_flags;
342 		off_t a_offlo;
343 		off_t a_offhi;
344 		struct lwp *a_l;
345 	} */ *ap = v;
346 	struct vnode *vp = ap->a_vp;
347 	struct buf *bp, *nbp;
348 	int s, error, passes, skipmeta, inodedeps_only, waitfor;
349 
350 	if (vp->v_type == VBLK &&
351 	    vp->v_specmountpoint != NULL &&
352 	    (vp->v_specmountpoint->mnt_flag & MNT_SOFTDEP))
353 		softdep_fsync_mountdev(vp);
354 
355 	inodedeps_only = DOINGSOFTDEP(vp) && (ap->a_flags & FSYNC_RECLAIM)
356 	    && vp->v_uobj.uo_npages == 0 && LIST_EMPTY(&vp->v_dirtyblkhd);
357 
358 	/*
359 	 * Flush all dirty data associated with a vnode.
360 	 */
361 
362 	if (vp->v_type == VREG || vp->v_type == VBLK) {
363 		simple_lock(&vp->v_interlock);
364 		error = VOP_PUTPAGES(vp, 0, 0, PGO_ALLPAGES | PGO_CLEANIT |
365 		    ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0));
366 		if (error) {
367 			return error;
368 		}
369 	}
370 
371 	passes = NIADDR + 1;
372 	skipmeta = 0;
373 	if (ap->a_flags & FSYNC_WAIT)
374 		skipmeta = 1;
375 	s = splbio();
376 
377 loop:
378 	LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs)
379 		bp->b_flags &= ~B_SCANNED;
380 	for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
381 		nbp = LIST_NEXT(bp, b_vnbufs);
382 		simple_lock(&bp->b_interlock);
383 		if (bp->b_flags & (B_BUSY | B_SCANNED)) {
384 			simple_unlock(&bp->b_interlock);
385 			continue;
386 		}
387 		if ((bp->b_flags & B_DELWRI) == 0)
388 			panic("ffs_fsync: not dirty");
389 		if (skipmeta && bp->b_lblkno < 0) {
390 			simple_unlock(&bp->b_interlock);
391 			continue;
392 		}
393 		simple_unlock(&bp->b_interlock);
394 		bp->b_flags |= B_BUSY | B_VFLUSH | B_SCANNED;
395 		splx(s);
396 		/*
397 		 * On our final pass through, do all I/O synchronously
398 		 * so that we can find out if our flush is failing
399 		 * because of write errors.
400 		 */
401 		if (passes > 0 || !(ap->a_flags & FSYNC_WAIT))
402 			(void) bawrite(bp);
403 		else if ((error = bwrite(bp)) != 0)
404 			return (error);
405 		s = splbio();
406 		/*
407 		 * Since we may have slept during the I/O, we need
408 		 * to start from a known point.
409 		 */
410 		nbp = LIST_FIRST(&vp->v_dirtyblkhd);
411 	}
412 	if (skipmeta) {
413 		skipmeta = 0;
414 		goto loop;
415 	}
416 	if (ap->a_flags & FSYNC_WAIT) {
417 		simple_lock(&global_v_numoutput_slock);
418 		while (vp->v_numoutput) {
419 			vp->v_flag |= VBWAIT;
420 			(void) ltsleep(&vp->v_numoutput, PRIBIO + 1,
421 			    "ffsfsync", 0, &global_v_numoutput_slock);
422 		}
423 		simple_unlock(&global_v_numoutput_slock);
424 		splx(s);
425 
426 		/*
427 		 * Ensure that any filesystem metadata associated
428 		 * with the vnode has been written.
429 		 */
430 		if ((error = softdep_sync_metadata(ap)) != 0)
431 			return (error);
432 
433 		s = splbio();
434 		if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
435 			/*
436 			* Block devices associated with filesystems may
437 			* have new I/O requests posted for them even if
438 			* the vnode is locked, so no amount of trying will
439 			* get them clean. Thus we give block devices a
440 			* good effort, then just give up. For all other file
441 			* types, go around and try again until it is clean.
442 			*/
443 			if (passes > 0) {
444 				passes--;
445 				goto loop;
446 			}
447 #ifdef DIAGNOSTIC
448 			if (vp->v_type != VBLK)
449 				vprint("ffs_fsync: dirty", vp);
450 #endif
451 		}
452 	}
453 	splx(s);
454 
455 	if (inodedeps_only)
456 		waitfor = 0;
457 	else
458 		waitfor = (ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0;
459 	error = ffs_update(vp, NULL, NULL, waitfor);
460 
461 	if (error == 0 && ap->a_flags & FSYNC_CACHE) {
462 		int i = 0;
463 		VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE,
464 			ap->a_l->l_proc->p_ucred, ap->a_l);
465 	}
466 
467 	return error;
468 }
469 
470 /*
471  * Reclaim an inode so that it can be used for other purposes.
472  */
473 int
474 ffs_reclaim(void *v)
475 {
476 	struct vop_reclaim_args /* {
477 		struct vnode *a_vp;
478 		struct lwp *a_l;
479 	} */ *ap = v;
480 	struct vnode *vp = ap->a_vp;
481 	struct inode *ip = VTOI(vp);
482 	struct ufsmount *ump = ip->i_ump;
483 	int error;
484 
485 	if ((error = ufs_reclaim(vp, ap->a_l)) != 0)
486 		return (error);
487 	if (ip->i_din.ffs1_din != NULL) {
488 		if (ump->um_fstype == UFS1)
489 			pool_put(&ffs_dinode1_pool, ip->i_din.ffs1_din);
490 		else
491 			pool_put(&ffs_dinode2_pool, ip->i_din.ffs2_din);
492 	}
493 	/*
494 	 * XXX MFS ends up here, too, to free an inode.  Should we create
495 	 * XXX a separate pool for MFS inodes?
496 	 */
497 	pool_put(&ffs_inode_pool, vp->v_data);
498 	vp->v_data = NULL;
499 	return (0);
500 }
501 
502 int
503 ffs_getpages(void *v)
504 {
505 	struct vop_getpages_args /* {
506 		struct vnode *a_vp;
507 		voff_t a_offset;
508 		struct vm_page **a_m;
509 		int *a_count;
510 		int a_centeridx;
511 		vm_prot_t a_access_type;
512 		int a_advice;
513 		int a_flags;
514 	} */ *ap = v;
515 	struct vnode *vp = ap->a_vp;
516 	struct inode *ip = VTOI(vp);
517 	struct fs *fs = ip->i_fs;
518 
519 	/*
520 	 * don't allow a softdep write to create pages for only part of a block.
521 	 * the dependency tracking requires that all pages be in memory for
522 	 * a block involved in a dependency.
523 	 */
524 
525 	if (ap->a_flags & PGO_OVERWRITE &&
526 	    (blkoff(fs, ap->a_offset) != 0 ||
527 	     blkoff(fs, *ap->a_count << PAGE_SHIFT) != 0) &&
528 	    DOINGSOFTDEP(ap->a_vp)) {
529 		if ((ap->a_flags & PGO_LOCKED) == 0) {
530 			simple_unlock(&vp->v_interlock);
531 		}
532 		return EINVAL;
533 	}
534 	return genfs_getpages(v);
535 }
536 
537 /*
538  * Return the last logical file offset that should be written for this file
539  * if we're doing a write that ends at "size".
540  */
541 
542 void
543 ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags)
544 {
545 	struct inode *ip = VTOI(vp);
546 	struct fs *fs = ip->i_fs;
547 	daddr_t olbn, nlbn;
548 
549 	KASSERT(flags & (GOP_SIZE_READ | GOP_SIZE_WRITE));
550 	KASSERT((flags & (GOP_SIZE_READ | GOP_SIZE_WRITE))
551 		!= (GOP_SIZE_READ | GOP_SIZE_WRITE));
552 
553 	olbn = lblkno(fs, ip->i_size);
554 	nlbn = lblkno(fs, size);
555 	if (nlbn < NDADDR && olbn <= nlbn) {
556 		*eobp = fragroundup(fs, size);
557 	} else {
558 		*eobp = blkroundup(fs, size);
559 	}
560 }
561 
562 int
563 ffs_openextattr(void *v)
564 {
565 	struct vop_openextattr_args /* {
566 		struct vnode *a_vp;
567 		struct ucred *a_cred;
568 		struct proc *a_p;
569 	} */ *ap = v;
570 	struct inode *ip = VTOI(ap->a_vp);
571 	struct fs *fs = ip->i_fs;
572 
573 	/* Not supported for UFS1 file systems. */
574 	if (fs->fs_magic == FS_UFS1_MAGIC)
575 		return (EOPNOTSUPP);
576 
577 	/* XXX Not implemented for UFS2 file systems. */
578 	return (EOPNOTSUPP);
579 }
580 
581 int
582 ffs_closeextattr(void *v)
583 {
584 	struct vop_closeextattr_args /* {
585 		struct vnode *a_vp;
586 		int a_commit;
587 		struct ucred *a_cred;
588 		struct proc *a_p;
589 	} */ *ap = v;
590 	struct inode *ip = VTOI(ap->a_vp);
591 	struct fs *fs = ip->i_fs;
592 
593 	/* Not supported for UFS1 file systems. */
594 	if (fs->fs_magic == FS_UFS1_MAGIC)
595 		return (EOPNOTSUPP);
596 
597 	/* XXX Not implemented for UFS2 file systems. */
598 	return (EOPNOTSUPP);
599 }
600 
601 int
602 ffs_getextattr(void *v)
603 {
604 	struct vop_getextattr_args /* {
605 		struct vnode *a_vp;
606 		int a_attrnamespace;
607 		const char *a_name;
608 		struct uio *a_uio;
609 		size_t *a_size;
610 		struct ucred *a_cred;
611 		struct proc *a_p;
612 	} */ *ap = v;
613 	struct inode *ip = VTOI(ap->a_vp);
614 	struct fs *fs = ip->i_fs;
615 
616 	if (fs->fs_magic == FS_UFS1_MAGIC) {
617 #ifdef UFS_EXTATTR
618 		return (ufs_getextattr(ap));
619 #else
620 		return (EOPNOTSUPP);
621 #endif
622 	}
623 
624 	/* XXX Not implemented for UFS2 file systems. */
625 	return (EOPNOTSUPP);
626 }
627 
628 int
629 ffs_setextattr(void *v)
630 {
631 	struct vop_setextattr_args /* {
632 		struct vnode *a_vp;
633 		int a_attrnamespace;
634 		const char *a_name;
635 		struct uio *a_uio;
636 		struct ucred *a_cred;
637 		struct proc *a_p;
638 	} */ *ap = v;
639 	struct inode *ip = VTOI(ap->a_vp);
640 	struct fs *fs = ip->i_fs;
641 
642 	if (fs->fs_magic == FS_UFS1_MAGIC) {
643 #ifdef UFS_EXTATTR
644 		return (ufs_setextattr(ap));
645 #else
646 		return (EOPNOTSUPP);
647 #endif
648 	}
649 
650 	/* XXX Not implemented for UFS2 file systems. */
651 	return (EOPNOTSUPP);
652 }
653 
654 int
655 ffs_listextattr(void *v)
656 {
657 	struct vop_listextattr_args /* {
658 		struct vnode *a_vp;
659 		int a_attrnamespace;
660 		struct uio *a_uio;
661 		size_t *a_size;
662 		struct ucred *a_cred;
663 		struct proc *a_p;
664 	} */ *ap = v;
665 	struct inode *ip = VTOI(ap->a_vp);
666 	struct fs *fs = ip->i_fs;
667 
668 	/* Not supported for UFS1 file systems. */
669 	if (fs->fs_magic == FS_UFS1_MAGIC)
670 		return (EOPNOTSUPP);
671 
672 	/* XXX Not implemented for UFS2 file systems. */
673 	return (EOPNOTSUPP);
674 }
675 
676 int
677 ffs_deleteextattr(void *v)
678 {
679 	struct vop_deleteextattr_args /* {
680 		struct vnode *a_vp;
681 		int a_attrnamespace;
682 		struct ucred *a_cred;
683 		struct proc *a_p;
684 	} */ *ap = v;
685 	struct inode *ip = VTOI(ap->a_vp);
686 	struct fs *fs = ip->i_fs;
687 
688 	if (fs->fs_magic == FS_UFS1_MAGIC) {
689 #ifdef UFS_EXTATTR
690 		return (ufs_deleteextattr(ap));
691 #else
692 		return (EOPNOTSUPP);
693 #endif
694 	}
695 
696 	/* XXX Not implemented for UFS2 file systems. */
697 	return (EOPNOTSUPP);
698 }
699