xref: /netbsd/sys/ufs/lfs/lfs_vnops.c (revision bf9ec67e)
1 /*	$NetBSD: lfs_vnops.c,v 1.64 2002/05/17 21:42:38 perseant Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Konrad E. Schroder <perseant@hhhh.org>.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the NetBSD
21  *      Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 /*
39  * Copyright (c) 1986, 1989, 1991, 1993, 1995
40  *	The Regents of the University of California.  All rights reserved.
41  *
42  * Redistribution and use in source and binary forms, with or without
43  * modification, are permitted provided that the following conditions
44  * are met:
45  * 1. Redistributions of source code must retain the above copyright
46  *    notice, this list of conditions and the following disclaimer.
47  * 2. Redistributions in binary form must reproduce the above copyright
48  *    notice, this list of conditions and the following disclaimer in the
49  *    documentation and/or other materials provided with the distribution.
50  * 3. All advertising materials mentioning features or use of this software
51  *    must display the following acknowledgement:
52  *	This product includes software developed by the University of
53  *	California, Berkeley and its contributors.
54  * 4. Neither the name of the University nor the names of its contributors
55  *    may be used to endorse or promote products derived from this software
56  *    without specific prior written permission.
57  *
58  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68  * SUCH DAMAGE.
69  *
70  *	@(#)lfs_vnops.c	8.13 (Berkeley) 6/10/95
71  */
72 
73 #include <sys/cdefs.h>
74 __KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,v 1.64 2002/05/17 21:42:38 perseant Exp $");
75 
76 #include <sys/param.h>
77 #include <sys/systm.h>
78 #include <sys/namei.h>
79 #include <sys/resourcevar.h>
80 #include <sys/kernel.h>
81 #include <sys/file.h>
82 #include <sys/stat.h>
83 #include <sys/buf.h>
84 #include <sys/proc.h>
85 #include <sys/conf.h>
86 #include <sys/mount.h>
87 #include <sys/vnode.h>
88 #include <sys/malloc.h>
89 #include <sys/pool.h>
90 #include <sys/signalvar.h>
91 
92 #include <miscfs/fifofs/fifo.h>
93 #include <miscfs/genfs/genfs.h>
94 #include <miscfs/specfs/specdev.h>
95 
96 #include <ufs/ufs/inode.h>
97 #include <ufs/ufs/dir.h>
98 #include <ufs/ufs/ufsmount.h>
99 #include <ufs/ufs/ufs_extern.h>
100 
101 #include <ufs/lfs/lfs.h>
102 #include <ufs/lfs/lfs_extern.h>
103 
104 /* Global vfs data structures for lfs. */
105 int (**lfs_vnodeop_p)(void *);
106 const struct vnodeopv_entry_desc lfs_vnodeop_entries[] = {
107 	{ &vop_default_desc, vn_default_error },
108 	{ &vop_lookup_desc, ufs_lookup },		/* lookup */
109 	{ &vop_create_desc, lfs_create },		/* create */
110 	{ &vop_whiteout_desc, lfs_whiteout },		/* whiteout */
111 	{ &vop_mknod_desc, lfs_mknod },			/* mknod */
112 	{ &vop_open_desc, ufs_open },			/* open */
113 	{ &vop_close_desc, lfs_close },			/* close */
114 	{ &vop_access_desc, ufs_access },		/* access */
115 	{ &vop_getattr_desc, lfs_getattr },		/* getattr */
116 	{ &vop_setattr_desc, lfs_setattr },		/* setattr */
117 	{ &vop_read_desc, lfs_read },			/* read */
118 	{ &vop_write_desc, lfs_write },			/* write */
119 	{ &vop_lease_desc, ufs_lease_check },		/* lease */
120 	{ &vop_ioctl_desc, ufs_ioctl },			/* ioctl */
121 	{ &vop_fcntl_desc, ufs_fcntl },			/* fcntl */
122 	{ &vop_poll_desc, ufs_poll },			/* poll */
123 	{ &vop_revoke_desc, ufs_revoke },		/* revoke */
124 	{ &vop_mmap_desc, ufs_mmap },			/* mmap */
125 	{ &vop_fsync_desc, lfs_fsync },			/* fsync */
126 	{ &vop_seek_desc, ufs_seek },			/* seek */
127 	{ &vop_remove_desc, lfs_remove },		/* remove */
128 	{ &vop_link_desc, lfs_link },			/* link */
129 	{ &vop_rename_desc, lfs_rename },		/* rename */
130 	{ &vop_mkdir_desc, lfs_mkdir },			/* mkdir */
131 	{ &vop_rmdir_desc, lfs_rmdir },			/* rmdir */
132 	{ &vop_symlink_desc, lfs_symlink },		/* symlink */
133 	{ &vop_readdir_desc, ufs_readdir },		/* readdir */
134 	{ &vop_readlink_desc, ufs_readlink },		/* readlink */
135 	{ &vop_abortop_desc, ufs_abortop },		/* abortop */
136 	{ &vop_inactive_desc, lfs_inactive },		/* inactive */
137 	{ &vop_reclaim_desc, lfs_reclaim },		/* reclaim */
138 	{ &vop_lock_desc, ufs_lock },			/* lock */
139 	{ &vop_unlock_desc, ufs_unlock },		/* unlock */
140 	{ &vop_bmap_desc, ufs_bmap },			/* bmap */
141 	{ &vop_strategy_desc, ufs_strategy },		/* strategy */
142 	{ &vop_print_desc, ufs_print },			/* print */
143 	{ &vop_islocked_desc, ufs_islocked },		/* islocked */
144 	{ &vop_pathconf_desc, ufs_pathconf },		/* pathconf */
145 	{ &vop_advlock_desc, ufs_advlock },		/* advlock */
146 	{ &vop_blkatoff_desc, lfs_blkatoff },		/* blkatoff */
147 	{ &vop_valloc_desc, lfs_valloc },		/* valloc */
148 	{ &vop_balloc_desc, lfs_balloc },		/* balloc */
149 	{ &vop_vfree_desc, lfs_vfree },			/* vfree */
150 	{ &vop_truncate_desc, lfs_truncate },		/* truncate */
151 	{ &vop_update_desc, lfs_update },		/* update */
152 	{ &vop_bwrite_desc, lfs_bwrite },		/* bwrite */
153 	{ &vop_getpages_desc, lfs_getpages },		/* getpages */
154 	{ &vop_putpages_desc, lfs_putpages },		/* putpages */
155 	{ NULL, NULL }
156 };
157 const struct vnodeopv_desc lfs_vnodeop_opv_desc =
158 	{ &lfs_vnodeop_p, lfs_vnodeop_entries };
159 
160 int (**lfs_specop_p)(void *);
161 const struct vnodeopv_entry_desc lfs_specop_entries[] = {
162 	{ &vop_default_desc, vn_default_error },
163 	{ &vop_lookup_desc, spec_lookup },		/* lookup */
164 	{ &vop_create_desc, spec_create },		/* create */
165 	{ &vop_mknod_desc, spec_mknod },		/* mknod */
166 	{ &vop_open_desc, spec_open },			/* open */
167 	{ &vop_close_desc, ufsspec_close },		/* close */
168 	{ &vop_access_desc, ufs_access },		/* access */
169 	{ &vop_getattr_desc, lfs_getattr },		/* getattr */
170 	{ &vop_setattr_desc, lfs_setattr },		/* setattr */
171 	{ &vop_read_desc, ufsspec_read },		/* read */
172 	{ &vop_write_desc, ufsspec_write },		/* write */
173 	{ &vop_lease_desc, spec_lease_check },		/* lease */
174 	{ &vop_ioctl_desc, spec_ioctl },		/* ioctl */
175 	{ &vop_fcntl_desc, ufs_fcntl },			/* fcntl */
176 	{ &vop_poll_desc, spec_poll },			/* poll */
177 	{ &vop_revoke_desc, spec_revoke },		/* revoke */
178 	{ &vop_mmap_desc, spec_mmap },			/* mmap */
179 	{ &vop_fsync_desc, spec_fsync },		/* fsync */
180 	{ &vop_seek_desc, spec_seek },			/* seek */
181 	{ &vop_remove_desc, spec_remove },		/* remove */
182 	{ &vop_link_desc, spec_link },			/* link */
183 	{ &vop_rename_desc, spec_rename },		/* rename */
184 	{ &vop_mkdir_desc, spec_mkdir },		/* mkdir */
185 	{ &vop_rmdir_desc, spec_rmdir },		/* rmdir */
186 	{ &vop_symlink_desc, spec_symlink },		/* symlink */
187 	{ &vop_readdir_desc, spec_readdir },		/* readdir */
188 	{ &vop_readlink_desc, spec_readlink },		/* readlink */
189 	{ &vop_abortop_desc, spec_abortop },		/* abortop */
190 	{ &vop_inactive_desc, lfs_inactive },		/* inactive */
191 	{ &vop_reclaim_desc, lfs_reclaim },		/* reclaim */
192 	{ &vop_lock_desc, ufs_lock },			/* lock */
193 	{ &vop_unlock_desc, ufs_unlock },		/* unlock */
194 	{ &vop_bmap_desc, spec_bmap },			/* bmap */
195 	{ &vop_strategy_desc, spec_strategy },		/* strategy */
196 	{ &vop_print_desc, ufs_print },			/* print */
197 	{ &vop_islocked_desc, ufs_islocked },		/* islocked */
198 	{ &vop_pathconf_desc, spec_pathconf },		/* pathconf */
199 	{ &vop_advlock_desc, spec_advlock },		/* advlock */
200 	{ &vop_blkatoff_desc, spec_blkatoff },		/* blkatoff */
201 	{ &vop_valloc_desc, spec_valloc },		/* valloc */
202 	{ &vop_vfree_desc, lfs_vfree },			/* vfree */
203 	{ &vop_truncate_desc, spec_truncate },		/* truncate */
204 	{ &vop_update_desc, lfs_update },		/* update */
205 	{ &vop_bwrite_desc, vn_bwrite },		/* bwrite */
206 	{ &vop_getpages_desc, spec_getpages },		/* getpages */
207 	{ &vop_putpages_desc, spec_putpages },		/* putpages */
208 	{ NULL, NULL }
209 };
210 const struct vnodeopv_desc lfs_specop_opv_desc =
211 	{ &lfs_specop_p, lfs_specop_entries };
212 
213 int (**lfs_fifoop_p)(void *);
214 const struct vnodeopv_entry_desc lfs_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, lfs_getattr },		/* getattr */
223 	{ &vop_setattr_desc, lfs_setattr },		/* setattr */
224 	{ &vop_read_desc, ufsfifo_read },		/* read */
225 	{ &vop_write_desc, ufsfifo_write },		/* write */
226 	{ &vop_lease_desc, fifo_lease_check },		/* lease */
227 	{ &vop_ioctl_desc, fifo_ioctl },		/* ioctl */
228 	{ &vop_fcntl_desc, ufs_fcntl },			/* fcntl */
229 	{ &vop_poll_desc, fifo_poll },			/* poll */
230 	{ &vop_revoke_desc, fifo_revoke },		/* revoke */
231 	{ &vop_mmap_desc, fifo_mmap },			/* mmap */
232 	{ &vop_fsync_desc, fifo_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, lfs_inactive },		/* inactive */
244 	{ &vop_reclaim_desc, lfs_reclaim },		/* reclaim */
245 	{ &vop_lock_desc, ufs_lock },			/* lock */
246 	{ &vop_unlock_desc, ufs_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, ufs_islocked },		/* islocked */
251 	{ &vop_pathconf_desc, fifo_pathconf },		/* pathconf */
252 	{ &vop_advlock_desc, fifo_advlock },		/* advlock */
253 	{ &vop_blkatoff_desc, fifo_blkatoff },		/* blkatoff */
254 	{ &vop_valloc_desc, fifo_valloc },		/* valloc */
255 	{ &vop_vfree_desc, lfs_vfree },			/* vfree */
256 	{ &vop_truncate_desc, fifo_truncate },		/* truncate */
257 	{ &vop_update_desc, lfs_update },		/* update */
258 	{ &vop_bwrite_desc, lfs_bwrite },		/* bwrite */
259 	{ &vop_putpages_desc, fifo_putpages }, 		/* putpages */
260 	{ NULL, NULL }
261 };
262 const struct vnodeopv_desc lfs_fifoop_opv_desc =
263 	{ &lfs_fifoop_p, lfs_fifoop_entries };
264 
265 /*
266  * A function version of LFS_ITIMES, for the UFS functions which call ITIMES
267  */
268 void
269 lfs_itimes(struct inode *ip, struct timespec *acc, struct timespec *mod, struct timespec *cre)
270 {
271 	LFS_ITIMES(ip, acc, mod, cre);
272 }
273 
274 #define	LFS_READWRITE
275 #include <ufs/ufs/ufs_readwrite.c>
276 #undef	LFS_READWRITE
277 
278 /*
279  * Synch an open file.
280  */
281 /* ARGSUSED */
282 int
283 lfs_fsync(void *v)
284 {
285 	struct vop_fsync_args /* {
286 		struct vnode *a_vp;
287 		struct ucred *a_cred;
288 		int a_flags;
289 		off_t offlo;
290 		off_t offhi;
291 		struct proc *a_p;
292 	} */ *ap = v;
293 	struct vnode *vp = ap->a_vp;
294 	int error;
295 
296 	/* Ignore the trickle syncer */
297 	if (ap->a_flags & FSYNC_LAZY)
298 		return 0;
299 
300 	simple_lock(&vp->v_interlock);
301 	error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo),
302                     round_page(ap->a_offhi), PGO_CLEANIT | PGO_SYNCIO);
303 	if (error)
304 		return error;
305 	error = VOP_UPDATE(vp, NULL, NULL,
306 			   (ap->a_flags & FSYNC_WAIT) != 0 ? UPDATE_WAIT : 0);
307 #ifdef DEBUG
308 	/*
309 	 * If we were called from vinvalbuf and lfs_update
310 	 * didn't flush all our buffers, we're in trouble.
311 	 */
312 	if ((ap->a_flags & FSYNC_WAIT) && LIST_FIRST(&vp->v_dirtyblkhd) != NULL) {
313 		struct buf *bp;
314 
315 		bp = LIST_FIRST(&vp->v_dirtyblkhd);
316 		printf("lfs_fsync: ino %d failed to sync", VTOI(vp)->i_number);
317 		printf("lfs_fsync: iocount = %d\n", VTOI(vp)->i_lfs->lfs_iocount);
318 		printf("lfs_fsync: flags are 0x%x, numoutput=%d\n",
319 			VTOI(vp)->i_flag, vp->v_numoutput);
320 		printf("lfs_fsync: writecount=%ld\n", vp->v_writecount);
321 		printf("lfs_fsync: first bp: %p, flags=0x%lx, lbn=%d\n",
322 			bp, bp->b_flags, bp->b_lblkno);
323 	}
324 #endif
325 	return error;
326 }
327 
328 /*
329  * Take IN_ADIROP off, then call ufs_inactive.
330  */
331 int
332 lfs_inactive(void *v)
333 {
334 	struct vop_inactive_args /* {
335 		struct vnode *a_vp;
336 		struct proc *a_p;
337 	} */ *ap = v;
338 	struct inode *ip = VTOI(ap->a_vp);
339 
340 	if (ip->i_flag & IN_ADIROP)
341 		--ip->i_lfs->lfs_nadirop;
342 	ip->i_flag &= ~IN_ADIROP;
343 	return ufs_inactive(v);
344 }
345 
346 /*
347  * These macros are used to bracket UFS directory ops, so that we can
348  * identify all the pages touched during directory ops which need to
349  * be ordered and flushed atomically, so that they may be recovered.
350  */
351 /*
352  * XXX KS - Because we have to mark nodes VDIROP in order to prevent
353  * the cache from reclaiming them while a dirop is in progress, we must
354  * also manage the number of nodes so marked (otherwise we can run out).
355  * We do this by setting lfs_dirvcount to the number of marked vnodes; it
356  * is decremented during segment write, when VDIROP is taken off.
357  */
358 #define	SET_DIROP(vp) lfs_set_dirop(vp)
359 static int lfs_set_dirop(struct vnode *);
360 extern int lfs_dirvcount;
361 
362 static int
363 lfs_set_dirop(struct vnode *vp)
364 {
365 	struct lfs *fs;
366 	int error;
367 
368 	fs = VTOI(vp)->i_lfs;
369 	/*
370 	 * We might need one directory block plus supporting indirect blocks,
371 	 * plus an inode block and ifile page for the new vnode.
372 	 */
373 	if ((error = lfs_reserve(fs, vp, btofsb(fs, (NIADDR + 3) << fs->lfs_bshift))) != 0)
374 		return (error);
375 	if (fs->lfs_dirops == 0)
376 		lfs_check(vp, LFS_UNUSED_LBN, 0);
377 	while (fs->lfs_writer || lfs_dirvcount > LFS_MAXDIROP) {
378 		if (fs->lfs_writer)
379 			tsleep(&fs->lfs_dirops, PRIBIO + 1, "lfs_sdirop", 0);
380 		if (lfs_dirvcount > LFS_MAXDIROP && fs->lfs_dirops == 0) {
381                 	++fs->lfs_writer;
382                 	lfs_flush(fs, 0);
383                 	if (--fs->lfs_writer == 0)
384                         	wakeup(&fs->lfs_dirops);
385 		}
386 
387 		if (lfs_dirvcount > LFS_MAXDIROP) {
388 #ifdef DEBUG_LFS
389 			printf("lfs_set_dirop: sleeping with dirops=%d, "
390 			       "dirvcount=%d\n", fs->lfs_dirops,
391 			       lfs_dirvcount);
392 #endif
393 			if ((error = tsleep(&lfs_dirvcount, PCATCH|PUSER,
394 					   "lfs_maxdirop", 0)) != 0) {
395 				lfs_reserve(fs, vp, -btofsb(fs, (NIADDR + 3) << fs->lfs_bshift));
396 				return error;
397 			}
398 		}
399 	}
400 	++fs->lfs_dirops;
401 	fs->lfs_doifile = 1;
402 
403 	/* Hold a reference so SET_ENDOP will be happy */
404 	lfs_vref(vp);
405 
406 	return 0;
407 }
408 
409 #define	SET_ENDOP(fs,vp,str) {						\
410 	--(fs)->lfs_dirops;						\
411 	if (!(fs)->lfs_dirops) {					\
412 		if ((fs)->lfs_nadirop) {				\
413 			panic("SET_ENDOP: %s: no dirops but nadirop=%d\n", \
414 			      (str), (fs)->lfs_nadirop);		\
415 		}							\
416 		wakeup(&(fs)->lfs_writer);				\
417 		lfs_check((vp),LFS_UNUSED_LBN,0);			\
418 	}								\
419 	lfs_reserve((fs), vp, -btofsb((fs), (NIADDR + 3) << (fs)->lfs_bshift)); /* XXX */	\
420 	lfs_vunref(vp);							\
421 }
422 
423 #define	MARK_VNODE(dvp)  do {                                           \
424         if (!((dvp)->v_flag & VDIROP)) {				\
425                 (void)lfs_vref(dvp);					\
426 		++lfs_dirvcount;					\
427 	}								\
428         (dvp)->v_flag |= VDIROP;					\
429 	if (!(VTOI(dvp)->i_flag & IN_ADIROP)) {				\
430 		++VTOI(dvp)->i_lfs->lfs_nadirop;			\
431 	}								\
432 	VTOI(dvp)->i_flag |= IN_ADIROP;					\
433 } while (0)
434 
435 #define UNMARK_VNODE(vp) lfs_unmark_vnode(vp)
436 
437 void lfs_unmark_vnode(struct vnode *vp)
438 {
439 	struct inode *ip;
440 
441 	ip = VTOI(vp);
442 
443 	if (ip->i_flag & IN_ADIROP)
444 		--ip->i_lfs->lfs_nadirop;
445 	ip->i_flag &= ~IN_ADIROP;
446 }
447 
448 int
449 lfs_symlink(void *v)
450 {
451 	struct vop_symlink_args /* {
452 		struct vnode *a_dvp;
453 		struct vnode **a_vpp;
454 		struct componentname *a_cnp;
455 		struct vattr *a_vap;
456 		char *a_target;
457 	} */ *ap = v;
458 	int error;
459 
460 	if ((error = SET_DIROP(ap->a_dvp)) != 0) {
461 		vput(ap->a_dvp);
462 		return error;
463 	}
464 	MARK_VNODE(ap->a_dvp);
465 	error = ufs_symlink(ap);
466 	UNMARK_VNODE(ap->a_dvp);
467 	if (*(ap->a_vpp))
468 		UNMARK_VNODE(*(ap->a_vpp));
469 	SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"symlink");
470 	return (error);
471 }
472 
473 int
474 lfs_mknod(void *v)
475 {
476 	struct vop_mknod_args	/* {
477 		struct vnode *a_dvp;
478 		struct vnode **a_vpp;
479 		struct componentname *a_cnp;
480 		struct vattr *a_vap;
481 		} */ *ap = v;
482         struct vattr *vap = ap->a_vap;
483         struct vnode **vpp = ap->a_vpp;
484         struct inode *ip;
485         int error;
486 	struct mount	*mp;
487 	ino_t		ino;
488 
489 	if ((error = SET_DIROP(ap->a_dvp)) != 0) {
490 		vput(ap->a_dvp);
491 		return error;
492 	}
493 	MARK_VNODE(ap->a_dvp);
494 	error = ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
495             ap->a_dvp, vpp, ap->a_cnp);
496 	UNMARK_VNODE(ap->a_dvp);
497         if (*(ap->a_vpp))
498                 UNMARK_VNODE(*(ap->a_vpp));
499 
500 	/* Either way we're done with the dirop at this point */
501 	SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"mknod");
502 
503         if (error)
504 		return (error);
505 
506         ip = VTOI(*vpp);
507 	mp  = (*vpp)->v_mount;
508 	ino = ip->i_number;
509         ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
510         if (vap->va_rdev != VNOVAL) {
511                 /*
512                  * Want to be able to use this to make badblock
513                  * inodes, so don't truncate the dev number.
514                  */
515 #if 0
516                 ip->i_ffs_rdev = ufs_rw32(vap->va_rdev,
517                     UFS_MPNEEDSWAP((*vpp)->v_mount));
518 #else
519                 ip->i_ffs_rdev = vap->va_rdev;
520 #endif
521         }
522 	/*
523 	 * Call fsync to write the vnode so that we don't have to deal with
524 	 * flushing it when it's marked VDIROP|VXLOCK.
525 	 *
526 	 * XXX KS - If we can't flush we also can't call vgone(), so must
527 	 * return.  But, that leaves this vnode in limbo, also not good.
528 	 * Can this ever happen (barring hardware failure)?
529 	 */
530 	if ((error = VOP_FSYNC(*vpp, NOCRED, FSYNC_WAIT, 0, 0, curproc)) != 0) {
531 		printf("Couldn't fsync in mknod (ino %d)---what do I do?\n",
532 		       VTOI(*vpp)->i_number);
533 		return (error);
534 	}
535         /*
536          * Remove vnode so that it will be reloaded by VFS_VGET and
537          * checked to see if it is an alias of an existing entry in
538          * the inode cache.
539          */
540 	/* Used to be vput, but that causes us to call VOP_INACTIVE twice. */
541 	VOP_UNLOCK(*vpp, 0);
542 	lfs_vunref(*vpp);
543         (*vpp)->v_type = VNON;
544         vgone(*vpp);
545 	error = VFS_VGET(mp, ino, vpp);
546 	if (error != 0) {
547 		*vpp = NULL;
548 		return (error);
549 	}
550         return (0);
551 }
552 
553 int
554 lfs_create(void *v)
555 {
556 	struct vop_create_args	/* {
557 		struct vnode *a_dvp;
558 		struct vnode **a_vpp;
559 		struct componentname *a_cnp;
560 		struct vattr *a_vap;
561 	} */ *ap = v;
562 	int error;
563 
564 	if ((error = SET_DIROP(ap->a_dvp)) != 0) {
565 		vput(ap->a_dvp);
566 		return error;
567 	}
568 	MARK_VNODE(ap->a_dvp);
569 	error = ufs_create(ap);
570 	UNMARK_VNODE(ap->a_dvp);
571         if (*(ap->a_vpp))
572                 UNMARK_VNODE(*(ap->a_vpp));
573 	SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"create");
574 	return (error);
575 }
576 
577 int
578 lfs_whiteout(void *v)
579 {
580 	struct vop_whiteout_args /* {
581 		struct vnode *a_dvp;
582 		struct componentname *a_cnp;
583 		int a_flags;
584 	} */ *ap = v;
585 	int error;
586 
587 	if ((error = SET_DIROP(ap->a_dvp)) != 0)
588 		/* XXX no unlock here? */
589 		return error;
590 	MARK_VNODE(ap->a_dvp);
591 	error = ufs_whiteout(ap);
592 	UNMARK_VNODE(ap->a_dvp);
593 	SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"whiteout");
594 	return (error);
595 }
596 
597 int
598 lfs_mkdir(void *v)
599 {
600 	struct vop_mkdir_args	/* {
601 		struct vnode *a_dvp;
602 		struct vnode **a_vpp;
603 		struct componentname *a_cnp;
604 		struct vattr *a_vap;
605 	} */ *ap = v;
606 	int error;
607 
608 	if ((error = SET_DIROP(ap->a_dvp)) != 0) {
609 		vput(ap->a_dvp);
610 		return error;
611 	}
612 	MARK_VNODE(ap->a_dvp);
613 	error = ufs_mkdir(ap);
614 	UNMARK_VNODE(ap->a_dvp);
615         if (*(ap->a_vpp))
616                 UNMARK_VNODE(*(ap->a_vpp));
617 	SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"mkdir");
618 	return (error);
619 }
620 
621 int
622 lfs_remove(void *v)
623 {
624 	struct vop_remove_args	/* {
625 		struct vnode *a_dvp;
626 		struct vnode *a_vp;
627 		struct componentname *a_cnp;
628 	} */ *ap = v;
629 	struct vnode *dvp, *vp;
630 	int error;
631 
632 	dvp = ap->a_dvp;
633 	vp = ap->a_vp;
634 	if ((error = SET_DIROP(dvp)) != 0) {
635 		if (dvp == vp)
636 			vrele(vp);
637 		else
638 			vput(vp);
639 		vput(dvp);
640 		return error;
641 	}
642 	MARK_VNODE(dvp);
643 	MARK_VNODE(vp);
644 	error = ufs_remove(ap);
645 	UNMARK_VNODE(dvp);
646 	UNMARK_VNODE(vp);
647 
648 	/*
649 	 * If ufs_remove failed, vp doesn't need to be VDIROP any more.
650 	 * If it succeeded, we can go ahead and wipe out vp, since
651 	 * its loss won't appear on disk until checkpoint, and by then
652 	 * dvp will have been written, completing the dirop.
653 	 */
654 	--lfs_dirvcount;
655 	vp->v_flag &= ~VDIROP;
656 	wakeup(&lfs_dirvcount);
657 	vrele(vp);
658 
659 	SET_ENDOP(VTOI(dvp)->i_lfs,dvp,"remove");
660 	return (error);
661 }
662 
663 int
664 lfs_rmdir(void *v)
665 {
666 	struct vop_rmdir_args	/* {
667 		struct vnodeop_desc *a_desc;
668 		struct vnode *a_dvp;
669 		struct vnode *a_vp;
670 		struct componentname *a_cnp;
671 	} */ *ap = v;
672 	int error;
673 
674 	if ((error = SET_DIROP(ap->a_dvp)) != 0) {
675 		vrele(ap->a_dvp);
676 		if (ap->a_vp->v_mountedhere != NULL)
677 			VOP_UNLOCK(ap->a_dvp, 0);
678 		vput(ap->a_vp);
679 		return error;
680 	}
681 	MARK_VNODE(ap->a_dvp);
682 	MARK_VNODE(ap->a_vp);
683 	error = ufs_rmdir(ap);
684 	UNMARK_VNODE(ap->a_dvp);
685 	UNMARK_VNODE(ap->a_vp);
686 
687 	/*
688 	 * If ufs_rmdir failed, vp doesn't need to be VDIROP any more.
689 	 * If it succeeded, we can go ahead and wipe out vp, since
690 	 * its loss won't appear on disk until checkpoint, and by then
691 	 * dvp will have been written, completing the dirop.
692 	 */
693 	--lfs_dirvcount;
694 	ap->a_vp->v_flag &= ~VDIROP;
695 	wakeup(&lfs_dirvcount);
696 	vrele(ap->a_vp);
697 
698 	SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"rmdir");
699 	return (error);
700 }
701 
702 int
703 lfs_link(void *v)
704 {
705 	struct vop_link_args	/* {
706 		struct vnode *a_dvp;
707 		struct vnode *a_vp;
708 		struct componentname *a_cnp;
709 	} */ *ap = v;
710 	int error;
711 
712 	if ((error = SET_DIROP(ap->a_dvp)) != 0) {
713 		vput(ap->a_dvp);
714 		return error;
715 	}
716 	MARK_VNODE(ap->a_dvp);
717 	error = ufs_link(ap);
718 	UNMARK_VNODE(ap->a_dvp);
719 	SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"link");
720 	return (error);
721 }
722 
723 int
724 lfs_rename(void *v)
725 {
726 	struct vop_rename_args	/* {
727 		struct vnode *a_fdvp;
728 		struct vnode *a_fvp;
729 		struct componentname *a_fcnp;
730 		struct vnode *a_tdvp;
731 		struct vnode *a_tvp;
732 		struct componentname *a_tcnp;
733 	} */ *ap = v;
734 	struct vnode *tvp, *fvp, *tdvp, *fdvp;
735 	int error;
736 	struct lfs *fs;
737 
738 	fs = VTOI(ap->a_fdvp)->i_lfs;
739 	tvp = ap->a_tvp;
740 	tdvp = ap->a_tdvp;
741 	fvp = ap->a_fvp;
742 	fdvp = ap->a_fdvp;
743 
744 	/*
745 	 * Check for cross-device rename.
746 	 * If it is, we don't want to set dirops, just error out.
747 	 * (In particular note that MARK_VNODE(tdvp) will DTWT on
748 	 * a cross-device rename.)
749 	 *
750 	 * Copied from ufs_rename.
751 	 */
752 	if ((fvp->v_mount != tdvp->v_mount) ||
753 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
754 		error = EXDEV;
755 		goto errout;
756 	}
757 	if ((error = SET_DIROP(fdvp)) != 0)
758 		goto errout;
759 	MARK_VNODE(fdvp);
760 	MARK_VNODE(tdvp);
761 	error = ufs_rename(ap);
762 	UNMARK_VNODE(fdvp);
763 	UNMARK_VNODE(tdvp);
764 	SET_ENDOP(fs,fdvp,"rename");
765 	return (error);
766 
767     errout:
768 	VOP_ABORTOP(tdvp, ap->a_tcnp); /* XXX, why not in NFS? */
769 	if (tdvp == tvp)
770 		vrele(tdvp);
771 	else
772 		vput(tdvp);
773 	if (tvp)
774 		vput(tvp);
775 	VOP_ABORTOP(fdvp, ap->a_fcnp); /* XXX, why not in NFS? */
776 	vrele(fdvp);
777 	vrele(fvp);
778 	return (error);
779 }
780 
781 /* XXX hack to avoid calling ITIMES in getattr */
782 int
783 lfs_getattr(void *v)
784 {
785 	struct vop_getattr_args /* {
786 		struct vnode *a_vp;
787 		struct vattr *a_vap;
788 		struct ucred *a_cred;
789 		struct proc *a_p;
790 	} */ *ap = v;
791 	struct vnode *vp = ap->a_vp;
792 	struct inode *ip = VTOI(vp);
793 	struct vattr *vap = ap->a_vap;
794 	struct lfs *fs = ip->i_lfs;
795 	/*
796 	 * Copy from inode table
797 	 */
798 	vap->va_fsid = ip->i_dev;
799 	vap->va_fileid = ip->i_number;
800 	vap->va_mode = ip->i_ffs_mode & ~IFMT;
801 	vap->va_nlink = ip->i_ffs_nlink;
802 	vap->va_uid = ip->i_ffs_uid;
803 	vap->va_gid = ip->i_ffs_gid;
804 	vap->va_rdev = (dev_t)ip->i_ffs_rdev;
805 	vap->va_size = vp->v_size;
806 	vap->va_atime.tv_sec = ip->i_ffs_atime;
807 	vap->va_atime.tv_nsec = ip->i_ffs_atimensec;
808 	vap->va_mtime.tv_sec = ip->i_ffs_mtime;
809 	vap->va_mtime.tv_nsec = ip->i_ffs_mtimensec;
810 	vap->va_ctime.tv_sec = ip->i_ffs_ctime;
811 	vap->va_ctime.tv_nsec = ip->i_ffs_ctimensec;
812 	vap->va_flags = ip->i_ffs_flags;
813 	vap->va_gen = ip->i_ffs_gen;
814 	/* this doesn't belong here */
815 	if (vp->v_type == VBLK)
816 		vap->va_blocksize = BLKDEV_IOSIZE;
817 	else if (vp->v_type == VCHR)
818 		vap->va_blocksize = MAXBSIZE;
819 	else
820 		vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
821 	vap->va_bytes = fsbtob(fs, (u_quad_t)ip->i_ffs_blocks);
822 	vap->va_type = vp->v_type;
823 	vap->va_filerev = ip->i_modrev;
824 	return (0);
825 }
826 
827 /*
828  * Check to make sure the inode blocks won't choke the buffer
829  * cache, then call ufs_setattr as usual.
830  */
831 int
832 lfs_setattr(void *v)
833 {
834 	struct vop_getattr_args /* {
835 		struct vnode *a_vp;
836 		struct vattr *a_vap;
837 		struct ucred *a_cred;
838 		struct proc *a_p;
839 	} */ *ap = v;
840 	struct vnode *vp = ap->a_vp;
841 
842 	lfs_check(vp, LFS_UNUSED_LBN, 0);
843 	return ufs_setattr(v);
844 }
845 
846 /*
847  * Close called
848  *
849  * XXX -- we were using ufs_close, but since it updates the
850  * times on the inode, we might need to bump the uinodes
851  * count.
852  */
853 /* ARGSUSED */
854 int
855 lfs_close(void *v)
856 {
857 	struct vop_close_args /* {
858 		struct vnode *a_vp;
859 		int  a_fflag;
860 		struct ucred *a_cred;
861 		struct proc *a_p;
862 	} */ *ap = v;
863 	struct vnode *vp = ap->a_vp;
864 	struct inode *ip = VTOI(vp);
865 	struct timespec ts;
866 
867 	simple_lock(&vp->v_interlock);
868 	if (vp->v_usecount > 1) {
869 		TIMEVAL_TO_TIMESPEC(&time, &ts);
870 		LFS_ITIMES(ip, &ts, &ts, &ts);
871 	}
872 	simple_unlock(&vp->v_interlock);
873 	return (0);
874 }
875 
876 /*
877  * Reclaim an inode so that it can be used for other purposes.
878  */
879 int lfs_no_inactive = 0;
880 
881 int
882 lfs_reclaim(void *v)
883 {
884 	struct vop_reclaim_args /* {
885 		struct vnode *a_vp;
886 		struct proc *a_p;
887 	} */ *ap = v;
888 	struct vnode *vp = ap->a_vp;
889 	int error;
890 
891 	LFS_CLR_UINO(VTOI(vp), IN_ALLMOD);
892 	if ((error = ufs_reclaim(vp, ap->a_p)))
893 		return (error);
894 	pool_put(&lfs_inode_pool, vp->v_data);
895 	vp->v_data = NULL;
896 	return (0);
897 }
898 
899 int
900 lfs_getpages(void *v)
901 {
902 	struct vop_getpages_args /* {
903 		struct vnode *a_vp;
904 		voff_t a_offset;
905 		struct vm_page **a_m;
906 		int *a_count;
907 		int a_centeridx;
908 		vm_prot_t a_access_type;
909 		int a_advice;
910 		int a_flags;
911 	} */ *ap = v;
912 
913 	if ((ap->a_access_type & VM_PROT_WRITE) != 0) {
914 		LFS_SET_UINO(VTOI(ap->a_vp), IN_MODIFIED);
915 	}
916 	return genfs_compat_getpages(v);
917 }
918 
919 int
920 lfs_putpages(void *v)
921 {
922 	int error;
923 
924 	error = genfs_putpages(v);
925 	return error;
926 }
927