xref: /freebsd/sys/ufs/ffs/ffs_vnops.c (revision b601c69bdbe8755d26570261d7fd4c02ee4eff74)
1 /*
2  * Copyright (c) 1982, 1986, 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	@(#)ffs_vnops.c	8.15 (Berkeley) 5/14/95
34  * $FreeBSD$
35  */
36 
37 #include "opt_ffs.h"
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/resourcevar.h>
42 #include <sys/signalvar.h>
43 #include <sys/kernel.h>
44 #include <sys/stat.h>
45 #include <sys/bio.h>
46 #include <sys/buf.h>
47 #include <sys/proc.h>
48 #include <sys/mount.h>
49 #include <sys/vnode.h>
50 #include <sys/conf.h>
51 
52 #include <machine/limits.h>
53 
54 #include <vm/vm.h>
55 #include <vm/vm_page.h>
56 #include <vm/vm_object.h>
57 #include <vm/vm_extern.h>
58 
59 #include <ufs/ufs/extattr.h>
60 #include <ufs/ufs/quota.h>
61 #include <ufs/ufs/inode.h>
62 #include <ufs/ufs/ufsmount.h>
63 #include <ufs/ufs/ufs_extern.h>
64 
65 #include <ufs/ffs/fs.h>
66 #include <ufs/ffs/ffs_extern.h>
67 
68 static int	ffs_fsync __P((struct vop_fsync_args *));
69 static int	ffs_getpages __P((struct vop_getpages_args *));
70 static int	ffs_putpages __P((struct vop_putpages_args *));
71 static int	ffs_read __P((struct vop_read_args *));
72 static int	ffs_write __P((struct vop_write_args *));
73 
74 /* Global vfs data structures for ufs. */
75 vop_t **ffs_vnodeop_p;
76 static struct vnodeopv_entry_desc ffs_vnodeop_entries[] = {
77 	{ &vop_default_desc,		(vop_t *) ufs_vnoperate },
78 	{ &vop_fsync_desc,		(vop_t *) ffs_fsync },
79 	{ &vop_getpages_desc,		(vop_t *) ffs_getpages },
80 	{ &vop_putpages_desc,		(vop_t *) ffs_putpages },
81 	{ &vop_read_desc,		(vop_t *) ffs_read },
82 	{ &vop_balloc_desc,		(vop_t *) ffs_balloc },
83 	{ &vop_reallocblks_desc,	(vop_t *) ffs_reallocblks },
84 	{ &vop_write_desc,		(vop_t *) ffs_write },
85 #ifdef FFS_EXTATTR
86 	{ &vop_getextattr_desc, 	(vop_t *) ufs_vop_getextattr },
87 	{ &vop_setextattr_desc,		(vop_t *) ufs_vop_setextattr },
88 #endif
89 	{ NULL, NULL }
90 };
91 static struct vnodeopv_desc ffs_vnodeop_opv_desc =
92 	{ &ffs_vnodeop_p, ffs_vnodeop_entries };
93 
94 vop_t **ffs_specop_p;
95 static struct vnodeopv_entry_desc ffs_specop_entries[] = {
96 	{ &vop_default_desc,		(vop_t *) ufs_vnoperatespec },
97 	{ &vop_fsync_desc,		(vop_t *) ffs_fsync },
98 	{ &vop_copyonwrite_desc,	(vop_t *) ffs_copyonwrite },
99 	{ NULL, NULL }
100 };
101 static struct vnodeopv_desc ffs_specop_opv_desc =
102 	{ &ffs_specop_p, ffs_specop_entries };
103 
104 vop_t **ffs_fifoop_p;
105 static struct vnodeopv_entry_desc ffs_fifoop_entries[] = {
106 	{ &vop_default_desc,		(vop_t *) ufs_vnoperatefifo },
107 	{ &vop_fsync_desc,		(vop_t *) ffs_fsync },
108 	{ NULL, NULL }
109 };
110 static struct vnodeopv_desc ffs_fifoop_opv_desc =
111 	{ &ffs_fifoop_p, ffs_fifoop_entries };
112 
113 VNODEOP_SET(ffs_vnodeop_opv_desc);
114 VNODEOP_SET(ffs_specop_opv_desc);
115 VNODEOP_SET(ffs_fifoop_opv_desc);
116 
117 #include <ufs/ufs/ufs_readwrite.c>
118 
119 /*
120  * Synch an open file.
121  */
122 /* ARGSUSED */
123 static int
124 ffs_fsync(ap)
125 	struct vop_fsync_args /* {
126 		struct vnode *a_vp;
127 		struct ucred *a_cred;
128 		int a_waitfor;
129 		struct proc *a_p;
130 	} */ *ap;
131 {
132 	struct vnode *vp = ap->a_vp;
133 	struct inode *ip = VTOI(vp);
134 	struct buf *bp;
135 	struct buf *nbp;
136 	int s, error, wait, passes, skipmeta;
137 	daddr_t lbn;
138 
139 	/*
140 	 * Snapshots have to be unlocked so they do not deadlock
141 	 * checking whether they need to copy their written buffers.
142 	 * We always hold a reference, so they cannot be removed
143 	 * out from underneath us.
144 	 */
145 	if (ip->i_flags & SF_SNAPSHOT)
146 		VOP_UNLOCK(vp, 0, ap->a_p);
147 	wait = (ap->a_waitfor == MNT_WAIT);
148 	if (vn_isdisk(vp, NULL)) {
149 		lbn = INT_MAX;
150 		if (vp->v_specmountpoint != NULL &&
151 		    (vp->v_specmountpoint->mnt_flag & MNT_SOFTDEP))
152 			softdep_fsync_mountdev(vp);
153 	} else {
154 		lbn = lblkno(ip->i_fs, (ip->i_size + ip->i_fs->fs_bsize - 1));
155 	}
156 
157 	/*
158 	 * Flush all dirty buffers associated with a vnode.
159 	 */
160 	passes = NIADDR + 1;
161 	skipmeta = 0;
162 	if (wait)
163 		skipmeta = 1;
164 	s = splbio();
165 loop:
166 	for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp;
167 	     bp = TAILQ_NEXT(bp, b_vnbufs))
168 		bp->b_flags &= ~B_SCANNED;
169 	for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
170 		nbp = TAILQ_NEXT(bp, b_vnbufs);
171 		/*
172 		 * Reasons to skip this buffer: it has already been considered
173 		 * on this pass, this pass is the first time through on a
174 		 * synchronous flush request and the buffer being considered
175 		 * is metadata, the buffer has dependencies that will cause
176 		 * it to be redirtied and it has not already been deferred,
177 		 * or it is already being written.
178 		 */
179 		if ((bp->b_flags & B_SCANNED) != 0)
180 			continue;
181 		bp->b_flags |= B_SCANNED;
182 		if ((skipmeta == 1 && bp->b_lblkno < 0))
183 			continue;
184 		if (!wait && LIST_FIRST(&bp->b_dep) != NULL &&
185 		    (bp->b_flags & B_DEFERRED) == 0 &&
186 		    buf_countdeps(bp, 0)) {
187 			bp->b_flags |= B_DEFERRED;
188 			continue;
189 		}
190 		if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT))
191 			continue;
192 		if ((bp->b_flags & B_DELWRI) == 0)
193 			panic("ffs_fsync: not dirty");
194 		if (vp != bp->b_vp)
195 			panic("ffs_fsync: vp != vp->b_vp");
196 		/*
197 		 * If this is a synchronous flush request, or it is not a
198 		 * file or device, start the write on this buffer immediatly.
199 		 */
200 		if (wait || (vp->v_type != VREG && vp->v_type != VBLK)) {
201 
202 			/*
203 			 * On our final pass through, do all I/O synchronously
204 			 * so that we can find out if our flush is failing
205 			 * because of write errors.
206 			 */
207 			if (passes > 0 || !wait) {
208 				if ((bp->b_flags & B_CLUSTEROK) && !wait) {
209 					BUF_UNLOCK(bp);
210 					(void) vfs_bio_awrite(bp);
211 				} else {
212 					bremfree(bp);
213 					splx(s);
214 					(void) bawrite(bp);
215 					s = splbio();
216 				}
217 			} else {
218 				bremfree(bp);
219 				splx(s);
220 				if ((error = bwrite(bp)) != 0)
221 					return (error);
222 				s = splbio();
223 			}
224 		} else if ((vp->v_type == VREG) && (bp->b_lblkno >= lbn)) {
225 			/*
226 			 * If the buffer is for data that has been truncated
227 			 * off the file, then throw it away.
228 			 */
229 			bremfree(bp);
230 			bp->b_flags |= B_INVAL | B_NOCACHE;
231 			splx(s);
232 			brelse(bp);
233 			s = splbio();
234 		} else {
235 			BUF_UNLOCK(bp);
236 			vfs_bio_awrite(bp);
237 		}
238 		/*
239 		 * Since we may have slept during the I/O, we need
240 		 * to start from a known point.
241 		 */
242 		nbp = TAILQ_FIRST(&vp->v_dirtyblkhd);
243 	}
244 	/*
245 	 * If we were asked to do this synchronously, then go back for
246 	 * another pass, this time doing the metadata.
247 	 */
248 	if (skipmeta) {
249 		skipmeta = 0;
250 		goto loop;
251 	}
252 
253 	if (wait) {
254 		while (vp->v_numoutput) {
255 			vp->v_flag |= VBWAIT;
256 			(void) tsleep((caddr_t)&vp->v_numoutput,
257 					PRIBIO + 4, "ffsfsn", 0);
258   		}
259 
260 		/*
261 		 * Ensure that any filesystem metatdata associated
262 		 * with the vnode has been written.
263 		 */
264 		splx(s);
265 		if ((error = softdep_sync_metadata(ap)) != 0)
266 			return (error);
267 		s = splbio();
268 
269 		if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) {
270 			/*
271 			 * Block devices associated with filesystems may
272 			 * have new I/O requests posted for them even if
273 			 * the vnode is locked, so no amount of trying will
274 			 * get them clean. Thus we give block devices a
275 			 * good effort, then just give up. For all other file
276 			 * types, go around and try again until it is clean.
277 			 */
278 			if (passes > 0) {
279 				passes -= 1;
280 				goto loop;
281 			}
282 #ifdef DIAGNOSTIC
283 			if (!vn_isdisk(vp, NULL))
284 				vprint("ffs_fsync: dirty", vp);
285 #endif
286 		}
287 	}
288 	splx(s);
289 	error = UFS_UPDATE(vp, wait);
290 	if (ip->i_flags & SF_SNAPSHOT)
291 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
292 	return (error);
293 }
294