Deleted Added
full compact
ffs_vnops.c (59241) ffs_vnops.c (60041)
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
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: head/sys/ufs/ffs/ffs_vnops.c 59241 2000-04-15 03:34:27Z rwatson $
34 * $FreeBSD: head/sys/ufs/ffs/ffs_vnops.c 60041 2000-05-05 09:59:14Z phk $
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>
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>
45#include <sys/buf.h>
46#include <sys/proc.h>
47#include <sys/mount.h>
48#include <sys/vnode.h>
49#include <sys/conf.h>
50
51#include <machine/limits.h>
52
53#include <vm/vm.h>
54#include <vm/vm_page.h>
55#include <vm/vm_object.h>
56#include <vm/vm_extern.h>
57
58#include <ufs/ufs/extattr.h>
59#include <ufs/ufs/quota.h>
60#include <ufs/ufs/inode.h>
61#include <ufs/ufs/ufsmount.h>
62#include <ufs/ufs/ufs_extern.h>
63
64#include <ufs/ffs/fs.h>
65#include <ufs/ffs/ffs_extern.h>
66
67static int ffs_fsync __P((struct vop_fsync_args *));
68static int ffs_getpages __P((struct vop_getpages_args *));
69static int ffs_putpages __P((struct vop_putpages_args *));
70static int ffs_read __P((struct vop_read_args *));
71static int ffs_write __P((struct vop_write_args *));
72
73/* Global vfs data structures for ufs. */
74vop_t **ffs_vnodeop_p;
75static struct vnodeopv_entry_desc ffs_vnodeop_entries[] = {
76 { &vop_default_desc, (vop_t *) ufs_vnoperate },
77 { &vop_fsync_desc, (vop_t *) ffs_fsync },
78 { &vop_getpages_desc, (vop_t *) ffs_getpages },
79 { &vop_putpages_desc, (vop_t *) ffs_putpages },
80 { &vop_read_desc, (vop_t *) ffs_read },
81 { &vop_balloc_desc, (vop_t *) ffs_balloc },
82 { &vop_reallocblks_desc, (vop_t *) ffs_reallocblks },
83 { &vop_write_desc, (vop_t *) ffs_write },
84#ifdef FFS_EXTATTR
85 { &vop_getextattr_desc, (vop_t *) ufs_vop_getextattr },
86 { &vop_setextattr_desc, (vop_t *) ufs_vop_setextattr },
87#endif
88 { NULL, NULL }
89};
90static struct vnodeopv_desc ffs_vnodeop_opv_desc =
91 { &ffs_vnodeop_p, ffs_vnodeop_entries };
92
93vop_t **ffs_specop_p;
94static struct vnodeopv_entry_desc ffs_specop_entries[] = {
95 { &vop_default_desc, (vop_t *) ufs_vnoperatespec },
96 { &vop_fsync_desc, (vop_t *) ffs_fsync },
97 { NULL, NULL }
98};
99static struct vnodeopv_desc ffs_specop_opv_desc =
100 { &ffs_specop_p, ffs_specop_entries };
101
102vop_t **ffs_fifoop_p;
103static struct vnodeopv_entry_desc ffs_fifoop_entries[] = {
104 { &vop_default_desc, (vop_t *) ufs_vnoperatefifo },
105 { &vop_fsync_desc, (vop_t *) ffs_fsync },
106 { NULL, NULL }
107};
108static struct vnodeopv_desc ffs_fifoop_opv_desc =
109 { &ffs_fifoop_p, ffs_fifoop_entries };
110
111VNODEOP_SET(ffs_vnodeop_opv_desc);
112VNODEOP_SET(ffs_specop_opv_desc);
113VNODEOP_SET(ffs_fifoop_opv_desc);
114
115#include <ufs/ufs/ufs_readwrite.c>
116
117/*
118 * Synch an open file.
119 */
120/* ARGSUSED */
121static int
122ffs_fsync(ap)
123 struct vop_fsync_args /* {
124 struct vnode *a_vp;
125 struct ucred *a_cred;
126 int a_waitfor;
127 struct proc *a_p;
128 } */ *ap;
129{
130 struct vnode *vp = ap->a_vp;
131 struct buf *bp;
132 struct buf *nbp;
133 int s, error, wait, passes, skipmeta;
134 daddr_t lbn;
135
136 wait = (ap->a_waitfor == MNT_WAIT);
137 if (vn_isdisk(vp, NULL)) {
138 lbn = INT_MAX;
139 if (vp->v_specmountpoint != NULL &&
140 (vp->v_specmountpoint->mnt_flag & MNT_SOFTDEP))
141 softdep_fsync_mountdev(vp);
142 } else {
143 struct inode *ip;
144 ip = VTOI(vp);
145 lbn = lblkno(ip->i_fs, (ip->i_size + ip->i_fs->fs_bsize - 1));
146 }
147
148 /*
149 * Flush all dirty buffers associated with a vnode.
150 */
151 passes = NIADDR + 1;
152 skipmeta = 0;
153 if (wait)
154 skipmeta = 1;
155 s = splbio();
156loop:
157 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp;
158 bp = TAILQ_NEXT(bp, b_vnbufs))
159 bp->b_flags &= ~B_SCANNED;
160 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
161 nbp = TAILQ_NEXT(bp, b_vnbufs);
162 /*
163 * Reasons to skip this buffer: it has already been considered
164 * on this pass, this pass is the first time through on a
165 * synchronous flush request and the buffer being considered
166 * is metadata, the buffer has dependencies that will cause
167 * it to be redirtied and it has not already been deferred,
168 * or it is already being written.
169 */
170 if ((bp->b_flags & B_SCANNED) != 0)
171 continue;
172 bp->b_flags |= B_SCANNED;
173 if ((skipmeta == 1 && bp->b_lblkno < 0))
174 continue;
175 if (!wait && LIST_FIRST(&bp->b_dep) != NULL &&
176 (bp->b_flags & B_DEFERRED) == 0 &&
177 bioops.io_countdeps && (*bioops.io_countdeps)(bp, 0)) {
178 bp->b_flags |= B_DEFERRED;
179 continue;
180 }
181 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT))
182 continue;
183 if ((bp->b_flags & B_DELWRI) == 0)
184 panic("ffs_fsync: not dirty");
185 if (vp != bp->b_vp)
186 panic("ffs_fsync: vp != vp->b_vp");
187 /*
188 * If this is a synchronous flush request, or it is not a
189 * file or device, start the write on this buffer immediatly.
190 */
191 if (wait || (vp->v_type != VREG && vp->v_type != VBLK)) {
192
193 /*
194 * On our final pass through, do all I/O synchronously
195 * so that we can find out if our flush is failing
196 * because of write errors.
197 */
198 if (passes > 0 || !wait) {
199 if ((bp->b_flags & B_CLUSTEROK) && !wait) {
200 BUF_UNLOCK(bp);
201 (void) vfs_bio_awrite(bp);
202 } else {
203 bremfree(bp);
204 splx(s);
205 (void) bawrite(bp);
206 s = splbio();
207 }
208 } else {
209 bremfree(bp);
210 splx(s);
211 if ((error = bwrite(bp)) != 0)
212 return (error);
213 s = splbio();
214 }
215 } else if ((vp->v_type == VREG) && (bp->b_lblkno >= lbn)) {
216 /*
217 * If the buffer is for data that has been truncated
218 * off the file, then throw it away.
219 */
220 bremfree(bp);
221 bp->b_flags |= B_INVAL | B_NOCACHE;
222 splx(s);
223 brelse(bp);
224 s = splbio();
225 } else {
226 BUF_UNLOCK(bp);
227 vfs_bio_awrite(bp);
228 }
229 /*
230 * Since we may have slept during the I/O, we need
231 * to start from a known point.
232 */
233 nbp = TAILQ_FIRST(&vp->v_dirtyblkhd);
234 }
235 /*
236 * If we were asked to do this synchronously, then go back for
237 * another pass, this time doing the metadata.
238 */
239 if (skipmeta) {
240 skipmeta = 0;
241 goto loop;
242 }
243
244 if (wait) {
245 while (vp->v_numoutput) {
246 vp->v_flag |= VBWAIT;
247 (void) tsleep((caddr_t)&vp->v_numoutput,
248 PRIBIO + 4, "ffsfsn", 0);
249 }
250
251 /*
252 * Ensure that any filesystem metatdata associated
253 * with the vnode has been written.
254 */
255 splx(s);
256 if ((error = softdep_sync_metadata(ap)) != 0)
257 return (error);
258 s = splbio();
259
260 if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) {
261 /*
262 * Block devices associated with filesystems may
263 * have new I/O requests posted for them even if
264 * the vnode is locked, so no amount of trying will
265 * get them clean. Thus we give block devices a
266 * good effort, then just give up. For all other file
267 * types, go around and try again until it is clean.
268 */
269 if (passes > 0) {
270 passes -= 1;
271 goto loop;
272 }
273#ifdef DIAGNOSTIC
274 if (!vn_isdisk(vp, NULL))
275 vprint("ffs_fsync: dirty", vp);
276#endif
277 }
278 }
279 splx(s);
280 return (UFS_UPDATE(vp, wait));
281}
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
68static int ffs_fsync __P((struct vop_fsync_args *));
69static int ffs_getpages __P((struct vop_getpages_args *));
70static int ffs_putpages __P((struct vop_putpages_args *));
71static int ffs_read __P((struct vop_read_args *));
72static int ffs_write __P((struct vop_write_args *));
73
74/* Global vfs data structures for ufs. */
75vop_t **ffs_vnodeop_p;
76static 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};
91static struct vnodeopv_desc ffs_vnodeop_opv_desc =
92 { &ffs_vnodeop_p, ffs_vnodeop_entries };
93
94vop_t **ffs_specop_p;
95static struct vnodeopv_entry_desc ffs_specop_entries[] = {
96 { &vop_default_desc, (vop_t *) ufs_vnoperatespec },
97 { &vop_fsync_desc, (vop_t *) ffs_fsync },
98 { NULL, NULL }
99};
100static struct vnodeopv_desc ffs_specop_opv_desc =
101 { &ffs_specop_p, ffs_specop_entries };
102
103vop_t **ffs_fifoop_p;
104static struct vnodeopv_entry_desc ffs_fifoop_entries[] = {
105 { &vop_default_desc, (vop_t *) ufs_vnoperatefifo },
106 { &vop_fsync_desc, (vop_t *) ffs_fsync },
107 { NULL, NULL }
108};
109static struct vnodeopv_desc ffs_fifoop_opv_desc =
110 { &ffs_fifoop_p, ffs_fifoop_entries };
111
112VNODEOP_SET(ffs_vnodeop_opv_desc);
113VNODEOP_SET(ffs_specop_opv_desc);
114VNODEOP_SET(ffs_fifoop_opv_desc);
115
116#include <ufs/ufs/ufs_readwrite.c>
117
118/*
119 * Synch an open file.
120 */
121/* ARGSUSED */
122static int
123ffs_fsync(ap)
124 struct vop_fsync_args /* {
125 struct vnode *a_vp;
126 struct ucred *a_cred;
127 int a_waitfor;
128 struct proc *a_p;
129 } */ *ap;
130{
131 struct vnode *vp = ap->a_vp;
132 struct buf *bp;
133 struct buf *nbp;
134 int s, error, wait, passes, skipmeta;
135 daddr_t lbn;
136
137 wait = (ap->a_waitfor == MNT_WAIT);
138 if (vn_isdisk(vp, NULL)) {
139 lbn = INT_MAX;
140 if (vp->v_specmountpoint != NULL &&
141 (vp->v_specmountpoint->mnt_flag & MNT_SOFTDEP))
142 softdep_fsync_mountdev(vp);
143 } else {
144 struct inode *ip;
145 ip = VTOI(vp);
146 lbn = lblkno(ip->i_fs, (ip->i_size + ip->i_fs->fs_bsize - 1));
147 }
148
149 /*
150 * Flush all dirty buffers associated with a vnode.
151 */
152 passes = NIADDR + 1;
153 skipmeta = 0;
154 if (wait)
155 skipmeta = 1;
156 s = splbio();
157loop:
158 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp;
159 bp = TAILQ_NEXT(bp, b_vnbufs))
160 bp->b_flags &= ~B_SCANNED;
161 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
162 nbp = TAILQ_NEXT(bp, b_vnbufs);
163 /*
164 * Reasons to skip this buffer: it has already been considered
165 * on this pass, this pass is the first time through on a
166 * synchronous flush request and the buffer being considered
167 * is metadata, the buffer has dependencies that will cause
168 * it to be redirtied and it has not already been deferred,
169 * or it is already being written.
170 */
171 if ((bp->b_flags & B_SCANNED) != 0)
172 continue;
173 bp->b_flags |= B_SCANNED;
174 if ((skipmeta == 1 && bp->b_lblkno < 0))
175 continue;
176 if (!wait && LIST_FIRST(&bp->b_dep) != NULL &&
177 (bp->b_flags & B_DEFERRED) == 0 &&
178 bioops.io_countdeps && (*bioops.io_countdeps)(bp, 0)) {
179 bp->b_flags |= B_DEFERRED;
180 continue;
181 }
182 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT))
183 continue;
184 if ((bp->b_flags & B_DELWRI) == 0)
185 panic("ffs_fsync: not dirty");
186 if (vp != bp->b_vp)
187 panic("ffs_fsync: vp != vp->b_vp");
188 /*
189 * If this is a synchronous flush request, or it is not a
190 * file or device, start the write on this buffer immediatly.
191 */
192 if (wait || (vp->v_type != VREG && vp->v_type != VBLK)) {
193
194 /*
195 * On our final pass through, do all I/O synchronously
196 * so that we can find out if our flush is failing
197 * because of write errors.
198 */
199 if (passes > 0 || !wait) {
200 if ((bp->b_flags & B_CLUSTEROK) && !wait) {
201 BUF_UNLOCK(bp);
202 (void) vfs_bio_awrite(bp);
203 } else {
204 bremfree(bp);
205 splx(s);
206 (void) bawrite(bp);
207 s = splbio();
208 }
209 } else {
210 bremfree(bp);
211 splx(s);
212 if ((error = bwrite(bp)) != 0)
213 return (error);
214 s = splbio();
215 }
216 } else if ((vp->v_type == VREG) && (bp->b_lblkno >= lbn)) {
217 /*
218 * If the buffer is for data that has been truncated
219 * off the file, then throw it away.
220 */
221 bremfree(bp);
222 bp->b_flags |= B_INVAL | B_NOCACHE;
223 splx(s);
224 brelse(bp);
225 s = splbio();
226 } else {
227 BUF_UNLOCK(bp);
228 vfs_bio_awrite(bp);
229 }
230 /*
231 * Since we may have slept during the I/O, we need
232 * to start from a known point.
233 */
234 nbp = TAILQ_FIRST(&vp->v_dirtyblkhd);
235 }
236 /*
237 * If we were asked to do this synchronously, then go back for
238 * another pass, this time doing the metadata.
239 */
240 if (skipmeta) {
241 skipmeta = 0;
242 goto loop;
243 }
244
245 if (wait) {
246 while (vp->v_numoutput) {
247 vp->v_flag |= VBWAIT;
248 (void) tsleep((caddr_t)&vp->v_numoutput,
249 PRIBIO + 4, "ffsfsn", 0);
250 }
251
252 /*
253 * Ensure that any filesystem metatdata associated
254 * with the vnode has been written.
255 */
256 splx(s);
257 if ((error = softdep_sync_metadata(ap)) != 0)
258 return (error);
259 s = splbio();
260
261 if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) {
262 /*
263 * Block devices associated with filesystems may
264 * have new I/O requests posted for them even if
265 * the vnode is locked, so no amount of trying will
266 * get them clean. Thus we give block devices a
267 * good effort, then just give up. For all other file
268 * types, go around and try again until it is clean.
269 */
270 if (passes > 0) {
271 passes -= 1;
272 goto loop;
273 }
274#ifdef DIAGNOSTIC
275 if (!vn_isdisk(vp, NULL))
276 vprint("ffs_fsync: dirty", vp);
277#endif
278 }
279 }
280 splx(s);
281 return (UFS_UPDATE(vp, wait));
282}