1*0a6a1f1dSLionel Sambuc /* $NetBSD: lfs_pages.c,v 1.7 2015/08/12 18:26:27 dholland Exp $ */
2*0a6a1f1dSLionel Sambuc
3*0a6a1f1dSLionel Sambuc /*-
4*0a6a1f1dSLionel Sambuc * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
5*0a6a1f1dSLionel Sambuc * All rights reserved.
6*0a6a1f1dSLionel Sambuc *
7*0a6a1f1dSLionel Sambuc * This code is derived from software contributed to The NetBSD Foundation
8*0a6a1f1dSLionel Sambuc * by Konrad E. Schroder <perseant@hhhh.org>.
9*0a6a1f1dSLionel Sambuc *
10*0a6a1f1dSLionel Sambuc * Redistribution and use in source and binary forms, with or without
11*0a6a1f1dSLionel Sambuc * modification, are permitted provided that the following conditions
12*0a6a1f1dSLionel Sambuc * are met:
13*0a6a1f1dSLionel Sambuc * 1. Redistributions of source code must retain the above copyright
14*0a6a1f1dSLionel Sambuc * notice, this list of conditions and the following disclaimer.
15*0a6a1f1dSLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
16*0a6a1f1dSLionel Sambuc * notice, this list of conditions and the following disclaimer in the
17*0a6a1f1dSLionel Sambuc * documentation and/or other materials provided with the distribution.
18*0a6a1f1dSLionel Sambuc *
19*0a6a1f1dSLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20*0a6a1f1dSLionel Sambuc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21*0a6a1f1dSLionel Sambuc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*0a6a1f1dSLionel Sambuc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23*0a6a1f1dSLionel Sambuc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*0a6a1f1dSLionel Sambuc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*0a6a1f1dSLionel Sambuc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*0a6a1f1dSLionel Sambuc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*0a6a1f1dSLionel Sambuc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*0a6a1f1dSLionel Sambuc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*0a6a1f1dSLionel Sambuc * POSSIBILITY OF SUCH DAMAGE.
30*0a6a1f1dSLionel Sambuc */
31*0a6a1f1dSLionel Sambuc /*
32*0a6a1f1dSLionel Sambuc * Copyright (c) 1986, 1989, 1991, 1993, 1995
33*0a6a1f1dSLionel Sambuc * The Regents of the University of California. All rights reserved.
34*0a6a1f1dSLionel Sambuc *
35*0a6a1f1dSLionel Sambuc * Redistribution and use in source and binary forms, with or without
36*0a6a1f1dSLionel Sambuc * modification, are permitted provided that the following conditions
37*0a6a1f1dSLionel Sambuc * are met:
38*0a6a1f1dSLionel Sambuc * 1. Redistributions of source code must retain the above copyright
39*0a6a1f1dSLionel Sambuc * notice, this list of conditions and the following disclaimer.
40*0a6a1f1dSLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
41*0a6a1f1dSLionel Sambuc * notice, this list of conditions and the following disclaimer in the
42*0a6a1f1dSLionel Sambuc * documentation and/or other materials provided with the distribution.
43*0a6a1f1dSLionel Sambuc * 3. Neither the name of the University nor the names of its contributors
44*0a6a1f1dSLionel Sambuc * may be used to endorse or promote products derived from this software
45*0a6a1f1dSLionel Sambuc * without specific prior written permission.
46*0a6a1f1dSLionel Sambuc *
47*0a6a1f1dSLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48*0a6a1f1dSLionel Sambuc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49*0a6a1f1dSLionel Sambuc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50*0a6a1f1dSLionel Sambuc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51*0a6a1f1dSLionel Sambuc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52*0a6a1f1dSLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53*0a6a1f1dSLionel Sambuc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54*0a6a1f1dSLionel Sambuc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55*0a6a1f1dSLionel Sambuc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56*0a6a1f1dSLionel Sambuc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57*0a6a1f1dSLionel Sambuc * SUCH DAMAGE.
58*0a6a1f1dSLionel Sambuc *
59*0a6a1f1dSLionel Sambuc * @(#)lfs_vnops.c 8.13 (Berkeley) 6/10/95
60*0a6a1f1dSLionel Sambuc */
61*0a6a1f1dSLionel Sambuc
62*0a6a1f1dSLionel Sambuc #include <sys/cdefs.h>
63*0a6a1f1dSLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: lfs_pages.c,v 1.7 2015/08/12 18:26:27 dholland Exp $");
64*0a6a1f1dSLionel Sambuc
65*0a6a1f1dSLionel Sambuc #ifdef _KERNEL_OPT
66*0a6a1f1dSLionel Sambuc #include "opt_compat_netbsd.h"
67*0a6a1f1dSLionel Sambuc #include "opt_uvm_page_trkown.h"
68*0a6a1f1dSLionel Sambuc #endif
69*0a6a1f1dSLionel Sambuc
70*0a6a1f1dSLionel Sambuc #include <sys/param.h>
71*0a6a1f1dSLionel Sambuc #include <sys/systm.h>
72*0a6a1f1dSLionel Sambuc #include <sys/namei.h>
73*0a6a1f1dSLionel Sambuc #include <sys/resourcevar.h>
74*0a6a1f1dSLionel Sambuc #include <sys/kernel.h>
75*0a6a1f1dSLionel Sambuc #include <sys/file.h>
76*0a6a1f1dSLionel Sambuc #include <sys/stat.h>
77*0a6a1f1dSLionel Sambuc #include <sys/buf.h>
78*0a6a1f1dSLionel Sambuc #include <sys/proc.h>
79*0a6a1f1dSLionel Sambuc #include <sys/mount.h>
80*0a6a1f1dSLionel Sambuc #include <sys/vnode.h>
81*0a6a1f1dSLionel Sambuc #include <sys/pool.h>
82*0a6a1f1dSLionel Sambuc #include <sys/signalvar.h>
83*0a6a1f1dSLionel Sambuc #include <sys/kauth.h>
84*0a6a1f1dSLionel Sambuc #include <sys/syslog.h>
85*0a6a1f1dSLionel Sambuc #include <sys/fstrans.h>
86*0a6a1f1dSLionel Sambuc
87*0a6a1f1dSLionel Sambuc #include <miscfs/fifofs/fifo.h>
88*0a6a1f1dSLionel Sambuc #include <miscfs/genfs/genfs.h>
89*0a6a1f1dSLionel Sambuc #include <miscfs/specfs/specdev.h>
90*0a6a1f1dSLionel Sambuc
91*0a6a1f1dSLionel Sambuc #include <ufs/lfs/ulfs_inode.h>
92*0a6a1f1dSLionel Sambuc #include <ufs/lfs/ulfsmount.h>
93*0a6a1f1dSLionel Sambuc #include <ufs/lfs/ulfs_bswap.h>
94*0a6a1f1dSLionel Sambuc #include <ufs/lfs/ulfs_extern.h>
95*0a6a1f1dSLionel Sambuc
96*0a6a1f1dSLionel Sambuc #include <uvm/uvm.h>
97*0a6a1f1dSLionel Sambuc #include <uvm/uvm_pmap.h>
98*0a6a1f1dSLionel Sambuc #include <uvm/uvm_stat.h>
99*0a6a1f1dSLionel Sambuc #include <uvm/uvm_pager.h>
100*0a6a1f1dSLionel Sambuc
101*0a6a1f1dSLionel Sambuc #include <ufs/lfs/lfs.h>
102*0a6a1f1dSLionel Sambuc #include <ufs/lfs/lfs_accessors.h>
103*0a6a1f1dSLionel Sambuc #include <ufs/lfs/lfs_kernel.h>
104*0a6a1f1dSLionel Sambuc #include <ufs/lfs/lfs_extern.h>
105*0a6a1f1dSLionel Sambuc
106*0a6a1f1dSLionel Sambuc extern pid_t lfs_writer_daemon;
107*0a6a1f1dSLionel Sambuc
108*0a6a1f1dSLionel Sambuc static int check_dirty(struct lfs *, struct vnode *, off_t, off_t, off_t, int, int, struct vm_page **);
109*0a6a1f1dSLionel Sambuc
110*0a6a1f1dSLionel Sambuc int
lfs_getpages(void * v)111*0a6a1f1dSLionel Sambuc lfs_getpages(void *v)
112*0a6a1f1dSLionel Sambuc {
113*0a6a1f1dSLionel Sambuc struct vop_getpages_args /* {
114*0a6a1f1dSLionel Sambuc struct vnode *a_vp;
115*0a6a1f1dSLionel Sambuc voff_t a_offset;
116*0a6a1f1dSLionel Sambuc struct vm_page **a_m;
117*0a6a1f1dSLionel Sambuc int *a_count;
118*0a6a1f1dSLionel Sambuc int a_centeridx;
119*0a6a1f1dSLionel Sambuc vm_prot_t a_access_type;
120*0a6a1f1dSLionel Sambuc int a_advice;
121*0a6a1f1dSLionel Sambuc int a_flags;
122*0a6a1f1dSLionel Sambuc } */ *ap = v;
123*0a6a1f1dSLionel Sambuc
124*0a6a1f1dSLionel Sambuc if (VTOI(ap->a_vp)->i_number == LFS_IFILE_INUM &&
125*0a6a1f1dSLionel Sambuc (ap->a_access_type & VM_PROT_WRITE) != 0) {
126*0a6a1f1dSLionel Sambuc return EPERM;
127*0a6a1f1dSLionel Sambuc }
128*0a6a1f1dSLionel Sambuc if ((ap->a_access_type & VM_PROT_WRITE) != 0) {
129*0a6a1f1dSLionel Sambuc mutex_enter(&lfs_lock);
130*0a6a1f1dSLionel Sambuc LFS_SET_UINO(VTOI(ap->a_vp), IN_MODIFIED);
131*0a6a1f1dSLionel Sambuc mutex_exit(&lfs_lock);
132*0a6a1f1dSLionel Sambuc }
133*0a6a1f1dSLionel Sambuc
134*0a6a1f1dSLionel Sambuc /*
135*0a6a1f1dSLionel Sambuc * we're relying on the fact that genfs_getpages() always read in
136*0a6a1f1dSLionel Sambuc * entire filesystem blocks.
137*0a6a1f1dSLionel Sambuc */
138*0a6a1f1dSLionel Sambuc return genfs_getpages(v);
139*0a6a1f1dSLionel Sambuc }
140*0a6a1f1dSLionel Sambuc
141*0a6a1f1dSLionel Sambuc /*
142*0a6a1f1dSLionel Sambuc * Wait for a page to become unbusy, possibly printing diagnostic messages
143*0a6a1f1dSLionel Sambuc * as well.
144*0a6a1f1dSLionel Sambuc *
145*0a6a1f1dSLionel Sambuc * Called with vp->v_interlock held; return with it held.
146*0a6a1f1dSLionel Sambuc */
147*0a6a1f1dSLionel Sambuc static void
wait_for_page(struct vnode * vp,struct vm_page * pg,const char * label)148*0a6a1f1dSLionel Sambuc wait_for_page(struct vnode *vp, struct vm_page *pg, const char *label)
149*0a6a1f1dSLionel Sambuc {
150*0a6a1f1dSLionel Sambuc KASSERT(mutex_owned(vp->v_interlock));
151*0a6a1f1dSLionel Sambuc if ((pg->flags & PG_BUSY) == 0)
152*0a6a1f1dSLionel Sambuc return; /* Nothing to wait for! */
153*0a6a1f1dSLionel Sambuc
154*0a6a1f1dSLionel Sambuc #if defined(DEBUG) && defined(UVM_PAGE_TRKOWN)
155*0a6a1f1dSLionel Sambuc static struct vm_page *lastpg;
156*0a6a1f1dSLionel Sambuc
157*0a6a1f1dSLionel Sambuc if (label != NULL && pg != lastpg) {
158*0a6a1f1dSLionel Sambuc if (pg->owner_tag) {
159*0a6a1f1dSLionel Sambuc printf("lfs_putpages[%d.%d]: %s: page %p owner %d.%d [%s]\n",
160*0a6a1f1dSLionel Sambuc curproc->p_pid, curlwp->l_lid, label,
161*0a6a1f1dSLionel Sambuc pg, pg->owner, pg->lowner, pg->owner_tag);
162*0a6a1f1dSLionel Sambuc } else {
163*0a6a1f1dSLionel Sambuc printf("lfs_putpages[%d.%d]: %s: page %p unowned?!\n",
164*0a6a1f1dSLionel Sambuc curproc->p_pid, curlwp->l_lid, label, pg);
165*0a6a1f1dSLionel Sambuc }
166*0a6a1f1dSLionel Sambuc }
167*0a6a1f1dSLionel Sambuc lastpg = pg;
168*0a6a1f1dSLionel Sambuc #endif
169*0a6a1f1dSLionel Sambuc
170*0a6a1f1dSLionel Sambuc pg->flags |= PG_WANTED;
171*0a6a1f1dSLionel Sambuc UVM_UNLOCK_AND_WAIT(pg, vp->v_interlock, 0, "lfsput", 0);
172*0a6a1f1dSLionel Sambuc mutex_enter(vp->v_interlock);
173*0a6a1f1dSLionel Sambuc }
174*0a6a1f1dSLionel Sambuc
175*0a6a1f1dSLionel Sambuc /*
176*0a6a1f1dSLionel Sambuc * This routine is called by lfs_putpages() when it can't complete the
177*0a6a1f1dSLionel Sambuc * write because a page is busy. This means that either (1) someone,
178*0a6a1f1dSLionel Sambuc * possibly the pagedaemon, is looking at this page, and will give it up
179*0a6a1f1dSLionel Sambuc * presently; or (2) we ourselves are holding the page busy in the
180*0a6a1f1dSLionel Sambuc * process of being written (either gathered or actually on its way to
181*0a6a1f1dSLionel Sambuc * disk). We don't need to give up the segment lock, but we might need
182*0a6a1f1dSLionel Sambuc * to call lfs_writeseg() to expedite the page's journey to disk.
183*0a6a1f1dSLionel Sambuc *
184*0a6a1f1dSLionel Sambuc * Called with vp->v_interlock held; return with it held.
185*0a6a1f1dSLionel Sambuc */
186*0a6a1f1dSLionel Sambuc /* #define BUSYWAIT */
187*0a6a1f1dSLionel Sambuc static void
write_and_wait(struct lfs * fs,struct vnode * vp,struct vm_page * pg,int seglocked,const char * label)188*0a6a1f1dSLionel Sambuc write_and_wait(struct lfs *fs, struct vnode *vp, struct vm_page *pg,
189*0a6a1f1dSLionel Sambuc int seglocked, const char *label)
190*0a6a1f1dSLionel Sambuc {
191*0a6a1f1dSLionel Sambuc KASSERT(mutex_owned(vp->v_interlock));
192*0a6a1f1dSLionel Sambuc #ifndef BUSYWAIT
193*0a6a1f1dSLionel Sambuc struct inode *ip = VTOI(vp);
194*0a6a1f1dSLionel Sambuc struct segment *sp = fs->lfs_sp;
195*0a6a1f1dSLionel Sambuc int count = 0;
196*0a6a1f1dSLionel Sambuc
197*0a6a1f1dSLionel Sambuc if (pg == NULL)
198*0a6a1f1dSLionel Sambuc return;
199*0a6a1f1dSLionel Sambuc
200*0a6a1f1dSLionel Sambuc while (pg->flags & PG_BUSY &&
201*0a6a1f1dSLionel Sambuc pg->uobject == &vp->v_uobj) {
202*0a6a1f1dSLionel Sambuc mutex_exit(vp->v_interlock);
203*0a6a1f1dSLionel Sambuc if (sp->cbpp - sp->bpp > 1) {
204*0a6a1f1dSLionel Sambuc /* Write gathered pages */
205*0a6a1f1dSLionel Sambuc lfs_updatemeta(sp);
206*0a6a1f1dSLionel Sambuc lfs_release_finfo(fs);
207*0a6a1f1dSLionel Sambuc (void) lfs_writeseg(fs, sp);
208*0a6a1f1dSLionel Sambuc
209*0a6a1f1dSLionel Sambuc /*
210*0a6a1f1dSLionel Sambuc * Reinitialize FIP
211*0a6a1f1dSLionel Sambuc */
212*0a6a1f1dSLionel Sambuc KASSERT(sp->vp == vp);
213*0a6a1f1dSLionel Sambuc lfs_acquire_finfo(fs, ip->i_number,
214*0a6a1f1dSLionel Sambuc ip->i_gen);
215*0a6a1f1dSLionel Sambuc }
216*0a6a1f1dSLionel Sambuc ++count;
217*0a6a1f1dSLionel Sambuc mutex_enter(vp->v_interlock);
218*0a6a1f1dSLionel Sambuc wait_for_page(vp, pg, label);
219*0a6a1f1dSLionel Sambuc }
220*0a6a1f1dSLionel Sambuc if (label != NULL && count > 1) {
221*0a6a1f1dSLionel Sambuc DLOG((DLOG_PAGE, "lfs_putpages[%d]: %s: %sn = %d\n",
222*0a6a1f1dSLionel Sambuc curproc->p_pid, label, (count > 0 ? "looping, " : ""),
223*0a6a1f1dSLionel Sambuc count));
224*0a6a1f1dSLionel Sambuc }
225*0a6a1f1dSLionel Sambuc #else
226*0a6a1f1dSLionel Sambuc preempt(1);
227*0a6a1f1dSLionel Sambuc #endif
228*0a6a1f1dSLionel Sambuc KASSERT(mutex_owned(vp->v_interlock));
229*0a6a1f1dSLionel Sambuc }
230*0a6a1f1dSLionel Sambuc
231*0a6a1f1dSLionel Sambuc /*
232*0a6a1f1dSLionel Sambuc * Make sure that for all pages in every block in the given range,
233*0a6a1f1dSLionel Sambuc * either all are dirty or all are clean. If any of the pages
234*0a6a1f1dSLionel Sambuc * we've seen so far are dirty, put the vnode on the paging chain,
235*0a6a1f1dSLionel Sambuc * and mark it IN_PAGING.
236*0a6a1f1dSLionel Sambuc *
237*0a6a1f1dSLionel Sambuc * If checkfirst != 0, don't check all the pages but return at the
238*0a6a1f1dSLionel Sambuc * first dirty page.
239*0a6a1f1dSLionel Sambuc */
240*0a6a1f1dSLionel Sambuc static int
check_dirty(struct lfs * fs,struct vnode * vp,off_t startoffset,off_t endoffset,off_t blkeof,int flags,int checkfirst,struct vm_page ** pgp)241*0a6a1f1dSLionel Sambuc check_dirty(struct lfs *fs, struct vnode *vp,
242*0a6a1f1dSLionel Sambuc off_t startoffset, off_t endoffset, off_t blkeof,
243*0a6a1f1dSLionel Sambuc int flags, int checkfirst, struct vm_page **pgp)
244*0a6a1f1dSLionel Sambuc {
245*0a6a1f1dSLionel Sambuc int by_list;
246*0a6a1f1dSLionel Sambuc struct vm_page *curpg = NULL; /* XXX: gcc */
247*0a6a1f1dSLionel Sambuc struct vm_page *pgs[MAXBSIZE / PAGE_SIZE], *pg;
248*0a6a1f1dSLionel Sambuc off_t soff = 0; /* XXX: gcc */
249*0a6a1f1dSLionel Sambuc voff_t off;
250*0a6a1f1dSLionel Sambuc int i;
251*0a6a1f1dSLionel Sambuc int nonexistent;
252*0a6a1f1dSLionel Sambuc int any_dirty; /* number of dirty pages */
253*0a6a1f1dSLionel Sambuc int dirty; /* number of dirty pages in a block */
254*0a6a1f1dSLionel Sambuc int tdirty;
255*0a6a1f1dSLionel Sambuc int pages_per_block = lfs_sb_getbsize(fs) >> PAGE_SHIFT;
256*0a6a1f1dSLionel Sambuc int pagedaemon = (curlwp == uvm.pagedaemon_lwp);
257*0a6a1f1dSLionel Sambuc
258*0a6a1f1dSLionel Sambuc KASSERT(mutex_owned(vp->v_interlock));
259*0a6a1f1dSLionel Sambuc ASSERT_MAYBE_SEGLOCK(fs);
260*0a6a1f1dSLionel Sambuc top:
261*0a6a1f1dSLionel Sambuc by_list = (vp->v_uobj.uo_npages <=
262*0a6a1f1dSLionel Sambuc ((endoffset - startoffset) >> PAGE_SHIFT) *
263*0a6a1f1dSLionel Sambuc UVM_PAGE_TREE_PENALTY);
264*0a6a1f1dSLionel Sambuc any_dirty = 0;
265*0a6a1f1dSLionel Sambuc
266*0a6a1f1dSLionel Sambuc if (by_list) {
267*0a6a1f1dSLionel Sambuc curpg = TAILQ_FIRST(&vp->v_uobj.memq);
268*0a6a1f1dSLionel Sambuc } else {
269*0a6a1f1dSLionel Sambuc soff = startoffset;
270*0a6a1f1dSLionel Sambuc }
271*0a6a1f1dSLionel Sambuc while (by_list || soff < MIN(blkeof, endoffset)) {
272*0a6a1f1dSLionel Sambuc if (by_list) {
273*0a6a1f1dSLionel Sambuc /*
274*0a6a1f1dSLionel Sambuc * Find the first page in a block. Skip
275*0a6a1f1dSLionel Sambuc * blocks outside our area of interest or beyond
276*0a6a1f1dSLionel Sambuc * the end of file.
277*0a6a1f1dSLionel Sambuc */
278*0a6a1f1dSLionel Sambuc KASSERT(curpg == NULL
279*0a6a1f1dSLionel Sambuc || (curpg->flags & PG_MARKER) == 0);
280*0a6a1f1dSLionel Sambuc if (pages_per_block > 1) {
281*0a6a1f1dSLionel Sambuc while (curpg &&
282*0a6a1f1dSLionel Sambuc ((curpg->offset & lfs_sb_getbmask(fs)) ||
283*0a6a1f1dSLionel Sambuc curpg->offset >= vp->v_size ||
284*0a6a1f1dSLionel Sambuc curpg->offset >= endoffset)) {
285*0a6a1f1dSLionel Sambuc curpg = TAILQ_NEXT(curpg, listq.queue);
286*0a6a1f1dSLionel Sambuc KASSERT(curpg == NULL ||
287*0a6a1f1dSLionel Sambuc (curpg->flags & PG_MARKER) == 0);
288*0a6a1f1dSLionel Sambuc }
289*0a6a1f1dSLionel Sambuc }
290*0a6a1f1dSLionel Sambuc if (curpg == NULL)
291*0a6a1f1dSLionel Sambuc break;
292*0a6a1f1dSLionel Sambuc soff = curpg->offset;
293*0a6a1f1dSLionel Sambuc }
294*0a6a1f1dSLionel Sambuc
295*0a6a1f1dSLionel Sambuc /*
296*0a6a1f1dSLionel Sambuc * Mark all pages in extended range busy; find out if any
297*0a6a1f1dSLionel Sambuc * of them are dirty.
298*0a6a1f1dSLionel Sambuc */
299*0a6a1f1dSLionel Sambuc nonexistent = dirty = 0;
300*0a6a1f1dSLionel Sambuc for (i = 0; i == 0 || i < pages_per_block; i++) {
301*0a6a1f1dSLionel Sambuc KASSERT(mutex_owned(vp->v_interlock));
302*0a6a1f1dSLionel Sambuc if (by_list && pages_per_block <= 1) {
303*0a6a1f1dSLionel Sambuc pgs[i] = pg = curpg;
304*0a6a1f1dSLionel Sambuc } else {
305*0a6a1f1dSLionel Sambuc off = soff + (i << PAGE_SHIFT);
306*0a6a1f1dSLionel Sambuc pgs[i] = pg = uvm_pagelookup(&vp->v_uobj, off);
307*0a6a1f1dSLionel Sambuc if (pg == NULL) {
308*0a6a1f1dSLionel Sambuc ++nonexistent;
309*0a6a1f1dSLionel Sambuc continue;
310*0a6a1f1dSLionel Sambuc }
311*0a6a1f1dSLionel Sambuc }
312*0a6a1f1dSLionel Sambuc KASSERT(pg != NULL);
313*0a6a1f1dSLionel Sambuc
314*0a6a1f1dSLionel Sambuc /*
315*0a6a1f1dSLionel Sambuc * If we're holding the segment lock, we can deadlock
316*0a6a1f1dSLionel Sambuc * against a process that has our page and is waiting
317*0a6a1f1dSLionel Sambuc * for the cleaner, while the cleaner waits for the
318*0a6a1f1dSLionel Sambuc * segment lock. Just bail in that case.
319*0a6a1f1dSLionel Sambuc */
320*0a6a1f1dSLionel Sambuc if ((pg->flags & PG_BUSY) &&
321*0a6a1f1dSLionel Sambuc (pagedaemon || LFS_SEGLOCK_HELD(fs))) {
322*0a6a1f1dSLionel Sambuc if (i > 0)
323*0a6a1f1dSLionel Sambuc uvm_page_unbusy(pgs, i);
324*0a6a1f1dSLionel Sambuc DLOG((DLOG_PAGE, "lfs_putpages: avoiding 3-way or pagedaemon deadlock\n"));
325*0a6a1f1dSLionel Sambuc if (pgp)
326*0a6a1f1dSLionel Sambuc *pgp = pg;
327*0a6a1f1dSLionel Sambuc KASSERT(mutex_owned(vp->v_interlock));
328*0a6a1f1dSLionel Sambuc return -1;
329*0a6a1f1dSLionel Sambuc }
330*0a6a1f1dSLionel Sambuc
331*0a6a1f1dSLionel Sambuc while (pg->flags & PG_BUSY) {
332*0a6a1f1dSLionel Sambuc wait_for_page(vp, pg, NULL);
333*0a6a1f1dSLionel Sambuc KASSERT(mutex_owned(vp->v_interlock));
334*0a6a1f1dSLionel Sambuc if (i > 0)
335*0a6a1f1dSLionel Sambuc uvm_page_unbusy(pgs, i);
336*0a6a1f1dSLionel Sambuc KASSERT(mutex_owned(vp->v_interlock));
337*0a6a1f1dSLionel Sambuc goto top;
338*0a6a1f1dSLionel Sambuc }
339*0a6a1f1dSLionel Sambuc pg->flags |= PG_BUSY;
340*0a6a1f1dSLionel Sambuc UVM_PAGE_OWN(pg, "lfs_putpages");
341*0a6a1f1dSLionel Sambuc
342*0a6a1f1dSLionel Sambuc pmap_page_protect(pg, VM_PROT_NONE);
343*0a6a1f1dSLionel Sambuc tdirty = (pmap_clear_modify(pg) ||
344*0a6a1f1dSLionel Sambuc (pg->flags & PG_CLEAN) == 0);
345*0a6a1f1dSLionel Sambuc dirty += tdirty;
346*0a6a1f1dSLionel Sambuc }
347*0a6a1f1dSLionel Sambuc if (pages_per_block > 0 && nonexistent >= pages_per_block) {
348*0a6a1f1dSLionel Sambuc if (by_list) {
349*0a6a1f1dSLionel Sambuc curpg = TAILQ_NEXT(curpg, listq.queue);
350*0a6a1f1dSLionel Sambuc } else {
351*0a6a1f1dSLionel Sambuc soff += lfs_sb_getbsize(fs);
352*0a6a1f1dSLionel Sambuc }
353*0a6a1f1dSLionel Sambuc continue;
354*0a6a1f1dSLionel Sambuc }
355*0a6a1f1dSLionel Sambuc
356*0a6a1f1dSLionel Sambuc any_dirty += dirty;
357*0a6a1f1dSLionel Sambuc KASSERT(nonexistent == 0);
358*0a6a1f1dSLionel Sambuc KASSERT(mutex_owned(vp->v_interlock));
359*0a6a1f1dSLionel Sambuc
360*0a6a1f1dSLionel Sambuc /*
361*0a6a1f1dSLionel Sambuc * If any are dirty make all dirty; unbusy them,
362*0a6a1f1dSLionel Sambuc * but if we were asked to clean, wire them so that
363*0a6a1f1dSLionel Sambuc * the pagedaemon doesn't bother us about them while
364*0a6a1f1dSLionel Sambuc * they're on their way to disk.
365*0a6a1f1dSLionel Sambuc */
366*0a6a1f1dSLionel Sambuc for (i = 0; i == 0 || i < pages_per_block; i++) {
367*0a6a1f1dSLionel Sambuc KASSERT(mutex_owned(vp->v_interlock));
368*0a6a1f1dSLionel Sambuc pg = pgs[i];
369*0a6a1f1dSLionel Sambuc KASSERT(!((pg->flags & PG_CLEAN) && (pg->flags & PG_DELWRI)));
370*0a6a1f1dSLionel Sambuc KASSERT(pg->flags & PG_BUSY);
371*0a6a1f1dSLionel Sambuc if (dirty) {
372*0a6a1f1dSLionel Sambuc pg->flags &= ~PG_CLEAN;
373*0a6a1f1dSLionel Sambuc if (flags & PGO_FREE) {
374*0a6a1f1dSLionel Sambuc /*
375*0a6a1f1dSLionel Sambuc * Wire the page so that
376*0a6a1f1dSLionel Sambuc * pdaemon doesn't see it again.
377*0a6a1f1dSLionel Sambuc */
378*0a6a1f1dSLionel Sambuc mutex_enter(&uvm_pageqlock);
379*0a6a1f1dSLionel Sambuc uvm_pagewire(pg);
380*0a6a1f1dSLionel Sambuc mutex_exit(&uvm_pageqlock);
381*0a6a1f1dSLionel Sambuc
382*0a6a1f1dSLionel Sambuc /* Suspended write flag */
383*0a6a1f1dSLionel Sambuc pg->flags |= PG_DELWRI;
384*0a6a1f1dSLionel Sambuc }
385*0a6a1f1dSLionel Sambuc }
386*0a6a1f1dSLionel Sambuc if (pg->flags & PG_WANTED)
387*0a6a1f1dSLionel Sambuc wakeup(pg);
388*0a6a1f1dSLionel Sambuc pg->flags &= ~(PG_WANTED|PG_BUSY);
389*0a6a1f1dSLionel Sambuc UVM_PAGE_OWN(pg, NULL);
390*0a6a1f1dSLionel Sambuc }
391*0a6a1f1dSLionel Sambuc
392*0a6a1f1dSLionel Sambuc if (checkfirst && any_dirty)
393*0a6a1f1dSLionel Sambuc break;
394*0a6a1f1dSLionel Sambuc
395*0a6a1f1dSLionel Sambuc if (by_list) {
396*0a6a1f1dSLionel Sambuc curpg = TAILQ_NEXT(curpg, listq.queue);
397*0a6a1f1dSLionel Sambuc } else {
398*0a6a1f1dSLionel Sambuc soff += MAX(PAGE_SIZE, lfs_sb_getbsize(fs));
399*0a6a1f1dSLionel Sambuc }
400*0a6a1f1dSLionel Sambuc }
401*0a6a1f1dSLionel Sambuc
402*0a6a1f1dSLionel Sambuc KASSERT(mutex_owned(vp->v_interlock));
403*0a6a1f1dSLionel Sambuc return any_dirty;
404*0a6a1f1dSLionel Sambuc }
405*0a6a1f1dSLionel Sambuc
406*0a6a1f1dSLionel Sambuc /*
407*0a6a1f1dSLionel Sambuc * lfs_putpages functions like genfs_putpages except that
408*0a6a1f1dSLionel Sambuc *
409*0a6a1f1dSLionel Sambuc * (1) It needs to bounds-check the incoming requests to ensure that
410*0a6a1f1dSLionel Sambuc * they are block-aligned; if they are not, expand the range and
411*0a6a1f1dSLionel Sambuc * do the right thing in case, e.g., the requested range is clean
412*0a6a1f1dSLionel Sambuc * but the expanded range is dirty.
413*0a6a1f1dSLionel Sambuc *
414*0a6a1f1dSLionel Sambuc * (2) It needs to explicitly send blocks to be written when it is done.
415*0a6a1f1dSLionel Sambuc * If VOP_PUTPAGES is called without the seglock held, we simply take
416*0a6a1f1dSLionel Sambuc * the seglock and let lfs_segunlock wait for us.
417*0a6a1f1dSLionel Sambuc * XXX There might be a bad situation if we have to flush a vnode while
418*0a6a1f1dSLionel Sambuc * XXX lfs_markv is in operation. As of this writing we panic in this
419*0a6a1f1dSLionel Sambuc * XXX case.
420*0a6a1f1dSLionel Sambuc *
421*0a6a1f1dSLionel Sambuc * Assumptions:
422*0a6a1f1dSLionel Sambuc *
423*0a6a1f1dSLionel Sambuc * (1) The caller does not hold any pages in this vnode busy. If it does,
424*0a6a1f1dSLionel Sambuc * there is a danger that when we expand the page range and busy the
425*0a6a1f1dSLionel Sambuc * pages we will deadlock.
426*0a6a1f1dSLionel Sambuc *
427*0a6a1f1dSLionel Sambuc * (2) We are called with vp->v_interlock held; we must return with it
428*0a6a1f1dSLionel Sambuc * released.
429*0a6a1f1dSLionel Sambuc *
430*0a6a1f1dSLionel Sambuc * (3) We don't absolutely have to free pages right away, provided that
431*0a6a1f1dSLionel Sambuc * the request does not have PGO_SYNCIO. When the pagedaemon gives
432*0a6a1f1dSLionel Sambuc * us a request with PGO_FREE, we take the pages out of the paging
433*0a6a1f1dSLionel Sambuc * queue and wake up the writer, which will handle freeing them for us.
434*0a6a1f1dSLionel Sambuc *
435*0a6a1f1dSLionel Sambuc * We ensure that for any filesystem block, all pages for that
436*0a6a1f1dSLionel Sambuc * block are either resident or not, even if those pages are higher
437*0a6a1f1dSLionel Sambuc * than EOF; that means that we will be getting requests to free
438*0a6a1f1dSLionel Sambuc * "unused" pages above EOF all the time, and should ignore them.
439*0a6a1f1dSLionel Sambuc *
440*0a6a1f1dSLionel Sambuc * (4) If we are called with PGO_LOCKED, the finfo array we are to write
441*0a6a1f1dSLionel Sambuc * into has been set up for us by lfs_writefile. If not, we will
442*0a6a1f1dSLionel Sambuc * have to handle allocating and/or freeing an finfo entry.
443*0a6a1f1dSLionel Sambuc *
444*0a6a1f1dSLionel Sambuc * XXX note that we're (ab)using PGO_LOCKED as "seglock held".
445*0a6a1f1dSLionel Sambuc */
446*0a6a1f1dSLionel Sambuc
447*0a6a1f1dSLionel Sambuc /* How many times to loop before we should start to worry */
448*0a6a1f1dSLionel Sambuc #define TOOMANY 4
449*0a6a1f1dSLionel Sambuc
450*0a6a1f1dSLionel Sambuc int
lfs_putpages(void * v)451*0a6a1f1dSLionel Sambuc lfs_putpages(void *v)
452*0a6a1f1dSLionel Sambuc {
453*0a6a1f1dSLionel Sambuc int error;
454*0a6a1f1dSLionel Sambuc struct vop_putpages_args /* {
455*0a6a1f1dSLionel Sambuc struct vnode *a_vp;
456*0a6a1f1dSLionel Sambuc voff_t a_offlo;
457*0a6a1f1dSLionel Sambuc voff_t a_offhi;
458*0a6a1f1dSLionel Sambuc int a_flags;
459*0a6a1f1dSLionel Sambuc } */ *ap = v;
460*0a6a1f1dSLionel Sambuc struct vnode *vp;
461*0a6a1f1dSLionel Sambuc struct inode *ip;
462*0a6a1f1dSLionel Sambuc struct lfs *fs;
463*0a6a1f1dSLionel Sambuc struct segment *sp;
464*0a6a1f1dSLionel Sambuc off_t origoffset, startoffset, endoffset, origendoffset, blkeof;
465*0a6a1f1dSLionel Sambuc off_t off, max_endoffset;
466*0a6a1f1dSLionel Sambuc bool seglocked, sync, pagedaemon, reclaim;
467*0a6a1f1dSLionel Sambuc struct vm_page *pg, *busypg;
468*0a6a1f1dSLionel Sambuc UVMHIST_FUNC("lfs_putpages"); UVMHIST_CALLED(ubchist);
469*0a6a1f1dSLionel Sambuc int oreclaim = 0;
470*0a6a1f1dSLionel Sambuc int donewriting = 0;
471*0a6a1f1dSLionel Sambuc #ifdef DEBUG
472*0a6a1f1dSLionel Sambuc int debug_n_again, debug_n_dirtyclean;
473*0a6a1f1dSLionel Sambuc #endif
474*0a6a1f1dSLionel Sambuc
475*0a6a1f1dSLionel Sambuc vp = ap->a_vp;
476*0a6a1f1dSLionel Sambuc ip = VTOI(vp);
477*0a6a1f1dSLionel Sambuc fs = ip->i_lfs;
478*0a6a1f1dSLionel Sambuc sync = (ap->a_flags & PGO_SYNCIO) != 0;
479*0a6a1f1dSLionel Sambuc reclaim = (ap->a_flags & PGO_RECLAIM) != 0;
480*0a6a1f1dSLionel Sambuc pagedaemon = (curlwp == uvm.pagedaemon_lwp);
481*0a6a1f1dSLionel Sambuc
482*0a6a1f1dSLionel Sambuc KASSERT(mutex_owned(vp->v_interlock));
483*0a6a1f1dSLionel Sambuc
484*0a6a1f1dSLionel Sambuc /* Putpages does nothing for metadata. */
485*0a6a1f1dSLionel Sambuc if (vp == fs->lfs_ivnode || vp->v_type != VREG) {
486*0a6a1f1dSLionel Sambuc mutex_exit(vp->v_interlock);
487*0a6a1f1dSLionel Sambuc return 0;
488*0a6a1f1dSLionel Sambuc }
489*0a6a1f1dSLionel Sambuc
490*0a6a1f1dSLionel Sambuc /*
491*0a6a1f1dSLionel Sambuc * If there are no pages, don't do anything.
492*0a6a1f1dSLionel Sambuc */
493*0a6a1f1dSLionel Sambuc if (vp->v_uobj.uo_npages == 0) {
494*0a6a1f1dSLionel Sambuc if (TAILQ_EMPTY(&vp->v_uobj.memq) &&
495*0a6a1f1dSLionel Sambuc (vp->v_iflag & VI_ONWORKLST) &&
496*0a6a1f1dSLionel Sambuc LIST_FIRST(&vp->v_dirtyblkhd) == NULL) {
497*0a6a1f1dSLionel Sambuc vp->v_iflag &= ~VI_WRMAPDIRTY;
498*0a6a1f1dSLionel Sambuc vn_syncer_remove_from_worklist(vp);
499*0a6a1f1dSLionel Sambuc }
500*0a6a1f1dSLionel Sambuc mutex_exit(vp->v_interlock);
501*0a6a1f1dSLionel Sambuc
502*0a6a1f1dSLionel Sambuc /* Remove us from paging queue, if we were on it */
503*0a6a1f1dSLionel Sambuc mutex_enter(&lfs_lock);
504*0a6a1f1dSLionel Sambuc if (ip->i_flags & IN_PAGING) {
505*0a6a1f1dSLionel Sambuc ip->i_flags &= ~IN_PAGING;
506*0a6a1f1dSLionel Sambuc TAILQ_REMOVE(&fs->lfs_pchainhd, ip, i_lfs_pchain);
507*0a6a1f1dSLionel Sambuc }
508*0a6a1f1dSLionel Sambuc mutex_exit(&lfs_lock);
509*0a6a1f1dSLionel Sambuc
510*0a6a1f1dSLionel Sambuc KASSERT(!mutex_owned(vp->v_interlock));
511*0a6a1f1dSLionel Sambuc return 0;
512*0a6a1f1dSLionel Sambuc }
513*0a6a1f1dSLionel Sambuc
514*0a6a1f1dSLionel Sambuc blkeof = lfs_blkroundup(fs, ip->i_size);
515*0a6a1f1dSLionel Sambuc
516*0a6a1f1dSLionel Sambuc /*
517*0a6a1f1dSLionel Sambuc * Ignore requests to free pages past EOF but in the same block
518*0a6a1f1dSLionel Sambuc * as EOF, unless the vnode is being reclaimed or the request
519*0a6a1f1dSLionel Sambuc * is synchronous. (If the request is sync, it comes from
520*0a6a1f1dSLionel Sambuc * lfs_truncate.)
521*0a6a1f1dSLionel Sambuc *
522*0a6a1f1dSLionel Sambuc * To avoid being flooded with this request, make these pages
523*0a6a1f1dSLionel Sambuc * look "active".
524*0a6a1f1dSLionel Sambuc */
525*0a6a1f1dSLionel Sambuc if (!sync && !reclaim &&
526*0a6a1f1dSLionel Sambuc ap->a_offlo >= ip->i_size && ap->a_offlo < blkeof) {
527*0a6a1f1dSLionel Sambuc origoffset = ap->a_offlo;
528*0a6a1f1dSLionel Sambuc for (off = origoffset; off < blkeof; off += lfs_sb_getbsize(fs)) {
529*0a6a1f1dSLionel Sambuc pg = uvm_pagelookup(&vp->v_uobj, off);
530*0a6a1f1dSLionel Sambuc KASSERT(pg != NULL);
531*0a6a1f1dSLionel Sambuc while (pg->flags & PG_BUSY) {
532*0a6a1f1dSLionel Sambuc pg->flags |= PG_WANTED;
533*0a6a1f1dSLionel Sambuc UVM_UNLOCK_AND_WAIT(pg, vp->v_interlock, 0,
534*0a6a1f1dSLionel Sambuc "lfsput2", 0);
535*0a6a1f1dSLionel Sambuc mutex_enter(vp->v_interlock);
536*0a6a1f1dSLionel Sambuc }
537*0a6a1f1dSLionel Sambuc mutex_enter(&uvm_pageqlock);
538*0a6a1f1dSLionel Sambuc uvm_pageactivate(pg);
539*0a6a1f1dSLionel Sambuc mutex_exit(&uvm_pageqlock);
540*0a6a1f1dSLionel Sambuc }
541*0a6a1f1dSLionel Sambuc ap->a_offlo = blkeof;
542*0a6a1f1dSLionel Sambuc if (ap->a_offhi > 0 && ap->a_offhi <= ap->a_offlo) {
543*0a6a1f1dSLionel Sambuc mutex_exit(vp->v_interlock);
544*0a6a1f1dSLionel Sambuc return 0;
545*0a6a1f1dSLionel Sambuc }
546*0a6a1f1dSLionel Sambuc }
547*0a6a1f1dSLionel Sambuc
548*0a6a1f1dSLionel Sambuc /*
549*0a6a1f1dSLionel Sambuc * Extend page range to start and end at block boundaries.
550*0a6a1f1dSLionel Sambuc * (For the purposes of VOP_PUTPAGES, fragments don't exist.)
551*0a6a1f1dSLionel Sambuc */
552*0a6a1f1dSLionel Sambuc origoffset = ap->a_offlo;
553*0a6a1f1dSLionel Sambuc origendoffset = ap->a_offhi;
554*0a6a1f1dSLionel Sambuc startoffset = origoffset & ~(lfs_sb_getbmask(fs));
555*0a6a1f1dSLionel Sambuc max_endoffset = (trunc_page(LLONG_MAX) >> lfs_sb_getbshift(fs))
556*0a6a1f1dSLionel Sambuc << lfs_sb_getbshift(fs);
557*0a6a1f1dSLionel Sambuc
558*0a6a1f1dSLionel Sambuc if (origendoffset == 0 || ap->a_flags & PGO_ALLPAGES) {
559*0a6a1f1dSLionel Sambuc endoffset = max_endoffset;
560*0a6a1f1dSLionel Sambuc origendoffset = endoffset;
561*0a6a1f1dSLionel Sambuc } else {
562*0a6a1f1dSLionel Sambuc origendoffset = round_page(ap->a_offhi);
563*0a6a1f1dSLionel Sambuc endoffset = round_page(lfs_blkroundup(fs, origendoffset));
564*0a6a1f1dSLionel Sambuc }
565*0a6a1f1dSLionel Sambuc
566*0a6a1f1dSLionel Sambuc KASSERT(startoffset > 0 || endoffset >= startoffset);
567*0a6a1f1dSLionel Sambuc if (startoffset == endoffset) {
568*0a6a1f1dSLionel Sambuc /* Nothing to do, why were we called? */
569*0a6a1f1dSLionel Sambuc mutex_exit(vp->v_interlock);
570*0a6a1f1dSLionel Sambuc DLOG((DLOG_PAGE, "lfs_putpages: startoffset = endoffset = %"
571*0a6a1f1dSLionel Sambuc PRId64 "\n", startoffset));
572*0a6a1f1dSLionel Sambuc return 0;
573*0a6a1f1dSLionel Sambuc }
574*0a6a1f1dSLionel Sambuc
575*0a6a1f1dSLionel Sambuc ap->a_offlo = startoffset;
576*0a6a1f1dSLionel Sambuc ap->a_offhi = endoffset;
577*0a6a1f1dSLionel Sambuc
578*0a6a1f1dSLionel Sambuc /*
579*0a6a1f1dSLionel Sambuc * If not cleaning, just send the pages through genfs_putpages
580*0a6a1f1dSLionel Sambuc * to be returned to the pool.
581*0a6a1f1dSLionel Sambuc */
582*0a6a1f1dSLionel Sambuc if (!(ap->a_flags & PGO_CLEANIT)) {
583*0a6a1f1dSLionel Sambuc DLOG((DLOG_PAGE, "lfs_putpages: no cleanit vn %p ino %d (flags %x)\n",
584*0a6a1f1dSLionel Sambuc vp, (int)ip->i_number, ap->a_flags));
585*0a6a1f1dSLionel Sambuc int r = genfs_putpages(v);
586*0a6a1f1dSLionel Sambuc KASSERT(!mutex_owned(vp->v_interlock));
587*0a6a1f1dSLionel Sambuc return r;
588*0a6a1f1dSLionel Sambuc }
589*0a6a1f1dSLionel Sambuc
590*0a6a1f1dSLionel Sambuc /* Set PGO_BUSYFAIL to avoid deadlocks */
591*0a6a1f1dSLionel Sambuc ap->a_flags |= PGO_BUSYFAIL;
592*0a6a1f1dSLionel Sambuc
593*0a6a1f1dSLionel Sambuc /*
594*0a6a1f1dSLionel Sambuc * Likewise, if we are asked to clean but the pages are not
595*0a6a1f1dSLionel Sambuc * dirty, we can just free them using genfs_putpages.
596*0a6a1f1dSLionel Sambuc */
597*0a6a1f1dSLionel Sambuc #ifdef DEBUG
598*0a6a1f1dSLionel Sambuc debug_n_dirtyclean = 0;
599*0a6a1f1dSLionel Sambuc #endif
600*0a6a1f1dSLionel Sambuc do {
601*0a6a1f1dSLionel Sambuc int r;
602*0a6a1f1dSLionel Sambuc KASSERT(mutex_owned(vp->v_interlock));
603*0a6a1f1dSLionel Sambuc
604*0a6a1f1dSLionel Sambuc /* Count the number of dirty pages */
605*0a6a1f1dSLionel Sambuc r = check_dirty(fs, vp, startoffset, endoffset, blkeof,
606*0a6a1f1dSLionel Sambuc ap->a_flags, 1, NULL);
607*0a6a1f1dSLionel Sambuc if (r < 0) {
608*0a6a1f1dSLionel Sambuc /* Pages are busy with another process */
609*0a6a1f1dSLionel Sambuc mutex_exit(vp->v_interlock);
610*0a6a1f1dSLionel Sambuc return EDEADLK;
611*0a6a1f1dSLionel Sambuc }
612*0a6a1f1dSLionel Sambuc if (r > 0) /* Some pages are dirty */
613*0a6a1f1dSLionel Sambuc break;
614*0a6a1f1dSLionel Sambuc
615*0a6a1f1dSLionel Sambuc /*
616*0a6a1f1dSLionel Sambuc * Sometimes pages are dirtied between the time that
617*0a6a1f1dSLionel Sambuc * we check and the time we try to clean them.
618*0a6a1f1dSLionel Sambuc * Instruct lfs_gop_write to return EDEADLK in this case
619*0a6a1f1dSLionel Sambuc * so we can write them properly.
620*0a6a1f1dSLionel Sambuc */
621*0a6a1f1dSLionel Sambuc ip->i_lfs_iflags |= LFSI_NO_GOP_WRITE;
622*0a6a1f1dSLionel Sambuc r = genfs_do_putpages(vp, startoffset, endoffset,
623*0a6a1f1dSLionel Sambuc ap->a_flags & ~PGO_SYNCIO, &busypg);
624*0a6a1f1dSLionel Sambuc ip->i_lfs_iflags &= ~LFSI_NO_GOP_WRITE;
625*0a6a1f1dSLionel Sambuc if (r != EDEADLK) {
626*0a6a1f1dSLionel Sambuc KASSERT(!mutex_owned(vp->v_interlock));
627*0a6a1f1dSLionel Sambuc return r;
628*0a6a1f1dSLionel Sambuc }
629*0a6a1f1dSLionel Sambuc
630*0a6a1f1dSLionel Sambuc /* One of the pages was busy. Start over. */
631*0a6a1f1dSLionel Sambuc mutex_enter(vp->v_interlock);
632*0a6a1f1dSLionel Sambuc wait_for_page(vp, busypg, "dirtyclean");
633*0a6a1f1dSLionel Sambuc #ifdef DEBUG
634*0a6a1f1dSLionel Sambuc ++debug_n_dirtyclean;
635*0a6a1f1dSLionel Sambuc #endif
636*0a6a1f1dSLionel Sambuc } while(1);
637*0a6a1f1dSLionel Sambuc
638*0a6a1f1dSLionel Sambuc #ifdef DEBUG
639*0a6a1f1dSLionel Sambuc if (debug_n_dirtyclean > TOOMANY)
640*0a6a1f1dSLionel Sambuc DLOG((DLOG_PAGE, "lfs_putpages: dirtyclean: looping, n = %d\n",
641*0a6a1f1dSLionel Sambuc debug_n_dirtyclean));
642*0a6a1f1dSLionel Sambuc #endif
643*0a6a1f1dSLionel Sambuc
644*0a6a1f1dSLionel Sambuc /*
645*0a6a1f1dSLionel Sambuc * Dirty and asked to clean.
646*0a6a1f1dSLionel Sambuc *
647*0a6a1f1dSLionel Sambuc * Pagedaemon can't actually write LFS pages; wake up
648*0a6a1f1dSLionel Sambuc * the writer to take care of that. The writer will
649*0a6a1f1dSLionel Sambuc * notice the pager inode queue and act on that.
650*0a6a1f1dSLionel Sambuc *
651*0a6a1f1dSLionel Sambuc * XXX We must drop the vp->interlock before taking the lfs_lock or we
652*0a6a1f1dSLionel Sambuc * get a nasty deadlock with lfs_flush_pchain().
653*0a6a1f1dSLionel Sambuc */
654*0a6a1f1dSLionel Sambuc if (pagedaemon) {
655*0a6a1f1dSLionel Sambuc mutex_exit(vp->v_interlock);
656*0a6a1f1dSLionel Sambuc mutex_enter(&lfs_lock);
657*0a6a1f1dSLionel Sambuc if (!(ip->i_flags & IN_PAGING)) {
658*0a6a1f1dSLionel Sambuc ip->i_flags |= IN_PAGING;
659*0a6a1f1dSLionel Sambuc TAILQ_INSERT_TAIL(&fs->lfs_pchainhd, ip, i_lfs_pchain);
660*0a6a1f1dSLionel Sambuc }
661*0a6a1f1dSLionel Sambuc wakeup(&lfs_writer_daemon);
662*0a6a1f1dSLionel Sambuc mutex_exit(&lfs_lock);
663*0a6a1f1dSLionel Sambuc preempt();
664*0a6a1f1dSLionel Sambuc KASSERT(!mutex_owned(vp->v_interlock));
665*0a6a1f1dSLionel Sambuc return EWOULDBLOCK;
666*0a6a1f1dSLionel Sambuc }
667*0a6a1f1dSLionel Sambuc
668*0a6a1f1dSLionel Sambuc /*
669*0a6a1f1dSLionel Sambuc * If this is a file created in a recent dirop, we can't flush its
670*0a6a1f1dSLionel Sambuc * inode until the dirop is complete. Drain dirops, then flush the
671*0a6a1f1dSLionel Sambuc * filesystem (taking care of any other pending dirops while we're
672*0a6a1f1dSLionel Sambuc * at it).
673*0a6a1f1dSLionel Sambuc */
674*0a6a1f1dSLionel Sambuc if ((ap->a_flags & (PGO_CLEANIT|PGO_LOCKED)) == PGO_CLEANIT &&
675*0a6a1f1dSLionel Sambuc (vp->v_uflag & VU_DIROP)) {
676*0a6a1f1dSLionel Sambuc DLOG((DLOG_PAGE, "lfs_putpages: flushing VU_DIROP\n"));
677*0a6a1f1dSLionel Sambuc
678*0a6a1f1dSLionel Sambuc lfs_writer_enter(fs, "ppdirop");
679*0a6a1f1dSLionel Sambuc
680*0a6a1f1dSLionel Sambuc /* Note if we hold the vnode locked */
681*0a6a1f1dSLionel Sambuc if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE)
682*0a6a1f1dSLionel Sambuc {
683*0a6a1f1dSLionel Sambuc DLOG((DLOG_PAGE, "lfs_putpages: dirop inode already locked\n"));
684*0a6a1f1dSLionel Sambuc } else {
685*0a6a1f1dSLionel Sambuc DLOG((DLOG_PAGE, "lfs_putpages: dirop inode not locked\n"));
686*0a6a1f1dSLionel Sambuc }
687*0a6a1f1dSLionel Sambuc mutex_exit(vp->v_interlock);
688*0a6a1f1dSLionel Sambuc
689*0a6a1f1dSLionel Sambuc mutex_enter(&lfs_lock);
690*0a6a1f1dSLionel Sambuc lfs_flush_fs(fs, sync ? SEGM_SYNC : 0);
691*0a6a1f1dSLionel Sambuc mutex_exit(&lfs_lock);
692*0a6a1f1dSLionel Sambuc
693*0a6a1f1dSLionel Sambuc mutex_enter(vp->v_interlock);
694*0a6a1f1dSLionel Sambuc lfs_writer_leave(fs);
695*0a6a1f1dSLionel Sambuc
696*0a6a1f1dSLionel Sambuc /* The flush will have cleaned out this vnode as well,
697*0a6a1f1dSLionel Sambuc no need to do more to it. */
698*0a6a1f1dSLionel Sambuc }
699*0a6a1f1dSLionel Sambuc
700*0a6a1f1dSLionel Sambuc /*
701*0a6a1f1dSLionel Sambuc * This is it. We are going to write some pages. From here on
702*0a6a1f1dSLionel Sambuc * down it's all just mechanics.
703*0a6a1f1dSLionel Sambuc *
704*0a6a1f1dSLionel Sambuc * Don't let genfs_putpages wait; lfs_segunlock will wait for us.
705*0a6a1f1dSLionel Sambuc */
706*0a6a1f1dSLionel Sambuc ap->a_flags &= ~PGO_SYNCIO;
707*0a6a1f1dSLionel Sambuc
708*0a6a1f1dSLionel Sambuc /*
709*0a6a1f1dSLionel Sambuc * If we've already got the seglock, flush the node and return.
710*0a6a1f1dSLionel Sambuc * The FIP has already been set up for us by lfs_writefile,
711*0a6a1f1dSLionel Sambuc * and FIP cleanup and lfs_updatemeta will also be done there,
712*0a6a1f1dSLionel Sambuc * unless genfs_putpages returns EDEADLK; then we must flush
713*0a6a1f1dSLionel Sambuc * what we have, and correct FIP and segment header accounting.
714*0a6a1f1dSLionel Sambuc */
715*0a6a1f1dSLionel Sambuc get_seglock:
716*0a6a1f1dSLionel Sambuc /*
717*0a6a1f1dSLionel Sambuc * If we are not called with the segment locked, lock it.
718*0a6a1f1dSLionel Sambuc * Account for a new FIP in the segment header, and set sp->vp.
719*0a6a1f1dSLionel Sambuc * (This should duplicate the setup at the top of lfs_writefile().)
720*0a6a1f1dSLionel Sambuc */
721*0a6a1f1dSLionel Sambuc seglocked = (ap->a_flags & PGO_LOCKED) != 0;
722*0a6a1f1dSLionel Sambuc if (!seglocked) {
723*0a6a1f1dSLionel Sambuc mutex_exit(vp->v_interlock);
724*0a6a1f1dSLionel Sambuc error = lfs_seglock(fs, SEGM_PROT | (sync ? SEGM_SYNC : 0));
725*0a6a1f1dSLionel Sambuc if (error != 0) {
726*0a6a1f1dSLionel Sambuc KASSERT(!mutex_owned(vp->v_interlock));
727*0a6a1f1dSLionel Sambuc return error;
728*0a6a1f1dSLionel Sambuc }
729*0a6a1f1dSLionel Sambuc mutex_enter(vp->v_interlock);
730*0a6a1f1dSLionel Sambuc lfs_acquire_finfo(fs, ip->i_number, ip->i_gen);
731*0a6a1f1dSLionel Sambuc }
732*0a6a1f1dSLionel Sambuc sp = fs->lfs_sp;
733*0a6a1f1dSLionel Sambuc KASSERT(sp->vp == NULL);
734*0a6a1f1dSLionel Sambuc sp->vp = vp;
735*0a6a1f1dSLionel Sambuc
736*0a6a1f1dSLionel Sambuc /* Note segments written by reclaim; only for debugging */
737*0a6a1f1dSLionel Sambuc if (vdead_check(vp, VDEAD_NOWAIT) != 0) {
738*0a6a1f1dSLionel Sambuc sp->seg_flags |= SEGM_RECLAIM;
739*0a6a1f1dSLionel Sambuc fs->lfs_reclino = ip->i_number;
740*0a6a1f1dSLionel Sambuc }
741*0a6a1f1dSLionel Sambuc
742*0a6a1f1dSLionel Sambuc /*
743*0a6a1f1dSLionel Sambuc * Ensure that the partial segment is marked SS_DIROP if this
744*0a6a1f1dSLionel Sambuc * vnode is a DIROP.
745*0a6a1f1dSLionel Sambuc */
746*0a6a1f1dSLionel Sambuc if (!seglocked && vp->v_uflag & VU_DIROP) {
747*0a6a1f1dSLionel Sambuc SEGSUM *ssp = sp->segsum;
748*0a6a1f1dSLionel Sambuc
749*0a6a1f1dSLionel Sambuc lfs_ss_setflags(fs, ssp,
750*0a6a1f1dSLionel Sambuc lfs_ss_getflags(fs, ssp) | (SS_DIROP|SS_CONT));
751*0a6a1f1dSLionel Sambuc }
752*0a6a1f1dSLionel Sambuc
753*0a6a1f1dSLionel Sambuc /*
754*0a6a1f1dSLionel Sambuc * Loop over genfs_putpages until all pages are gathered.
755*0a6a1f1dSLionel Sambuc * genfs_putpages() drops the interlock, so reacquire it if necessary.
756*0a6a1f1dSLionel Sambuc * Whenever we lose the interlock we have to rerun check_dirty, as
757*0a6a1f1dSLionel Sambuc * well, since more pages might have been dirtied in our absence.
758*0a6a1f1dSLionel Sambuc */
759*0a6a1f1dSLionel Sambuc #ifdef DEBUG
760*0a6a1f1dSLionel Sambuc debug_n_again = 0;
761*0a6a1f1dSLionel Sambuc #endif
762*0a6a1f1dSLionel Sambuc do {
763*0a6a1f1dSLionel Sambuc busypg = NULL;
764*0a6a1f1dSLionel Sambuc KASSERT(mutex_owned(vp->v_interlock));
765*0a6a1f1dSLionel Sambuc if (check_dirty(fs, vp, startoffset, endoffset, blkeof,
766*0a6a1f1dSLionel Sambuc ap->a_flags, 0, &busypg) < 0) {
767*0a6a1f1dSLionel Sambuc mutex_exit(vp->v_interlock);
768*0a6a1f1dSLionel Sambuc /* XXX why? --ks */
769*0a6a1f1dSLionel Sambuc mutex_enter(vp->v_interlock);
770*0a6a1f1dSLionel Sambuc write_and_wait(fs, vp, busypg, seglocked, NULL);
771*0a6a1f1dSLionel Sambuc if (!seglocked) {
772*0a6a1f1dSLionel Sambuc mutex_exit(vp->v_interlock);
773*0a6a1f1dSLionel Sambuc lfs_release_finfo(fs);
774*0a6a1f1dSLionel Sambuc lfs_segunlock(fs);
775*0a6a1f1dSLionel Sambuc mutex_enter(vp->v_interlock);
776*0a6a1f1dSLionel Sambuc }
777*0a6a1f1dSLionel Sambuc sp->vp = NULL;
778*0a6a1f1dSLionel Sambuc goto get_seglock;
779*0a6a1f1dSLionel Sambuc }
780*0a6a1f1dSLionel Sambuc
781*0a6a1f1dSLionel Sambuc busypg = NULL;
782*0a6a1f1dSLionel Sambuc KASSERT(!mutex_owned(&uvm_pageqlock));
783*0a6a1f1dSLionel Sambuc oreclaim = (ap->a_flags & PGO_RECLAIM);
784*0a6a1f1dSLionel Sambuc ap->a_flags &= ~PGO_RECLAIM;
785*0a6a1f1dSLionel Sambuc error = genfs_do_putpages(vp, startoffset, endoffset,
786*0a6a1f1dSLionel Sambuc ap->a_flags, &busypg);
787*0a6a1f1dSLionel Sambuc ap->a_flags |= oreclaim;
788*0a6a1f1dSLionel Sambuc
789*0a6a1f1dSLionel Sambuc if (error == EDEADLK || error == EAGAIN) {
790*0a6a1f1dSLionel Sambuc DLOG((DLOG_PAGE, "lfs_putpages: genfs_putpages returned"
791*0a6a1f1dSLionel Sambuc " %d ino %d off %jx (seg %d)\n", error,
792*0a6a1f1dSLionel Sambuc ip->i_number, (uintmax_t)lfs_sb_getoffset(fs),
793*0a6a1f1dSLionel Sambuc lfs_dtosn(fs, lfs_sb_getoffset(fs))));
794*0a6a1f1dSLionel Sambuc
795*0a6a1f1dSLionel Sambuc if (oreclaim) {
796*0a6a1f1dSLionel Sambuc mutex_enter(vp->v_interlock);
797*0a6a1f1dSLionel Sambuc write_and_wait(fs, vp, busypg, seglocked, "again");
798*0a6a1f1dSLionel Sambuc mutex_exit(vp->v_interlock);
799*0a6a1f1dSLionel Sambuc } else {
800*0a6a1f1dSLionel Sambuc if ((sp->seg_flags & SEGM_SINGLE) &&
801*0a6a1f1dSLionel Sambuc lfs_sb_getcurseg(fs) != fs->lfs_startseg)
802*0a6a1f1dSLionel Sambuc donewriting = 1;
803*0a6a1f1dSLionel Sambuc }
804*0a6a1f1dSLionel Sambuc } else if (error) {
805*0a6a1f1dSLionel Sambuc DLOG((DLOG_PAGE, "lfs_putpages: genfs_putpages returned"
806*0a6a1f1dSLionel Sambuc " %d ino %d off %jx (seg %d)\n", error,
807*0a6a1f1dSLionel Sambuc (int)ip->i_number, (uintmax_t)lfs_sb_getoffset(fs),
808*0a6a1f1dSLionel Sambuc lfs_dtosn(fs, lfs_sb_getoffset(fs))));
809*0a6a1f1dSLionel Sambuc }
810*0a6a1f1dSLionel Sambuc /* genfs_do_putpages loses the interlock */
811*0a6a1f1dSLionel Sambuc #ifdef DEBUG
812*0a6a1f1dSLionel Sambuc ++debug_n_again;
813*0a6a1f1dSLionel Sambuc #endif
814*0a6a1f1dSLionel Sambuc if (oreclaim && error == EAGAIN) {
815*0a6a1f1dSLionel Sambuc DLOG((DLOG_PAGE, "vp %p ino %d vi_flags %x a_flags %x avoiding vclean panic\n",
816*0a6a1f1dSLionel Sambuc vp, (int)ip->i_number, vp->v_iflag, ap->a_flags));
817*0a6a1f1dSLionel Sambuc mutex_enter(vp->v_interlock);
818*0a6a1f1dSLionel Sambuc }
819*0a6a1f1dSLionel Sambuc if (error == EDEADLK)
820*0a6a1f1dSLionel Sambuc mutex_enter(vp->v_interlock);
821*0a6a1f1dSLionel Sambuc } while (error == EDEADLK || (oreclaim && error == EAGAIN));
822*0a6a1f1dSLionel Sambuc #ifdef DEBUG
823*0a6a1f1dSLionel Sambuc if (debug_n_again > TOOMANY)
824*0a6a1f1dSLionel Sambuc DLOG((DLOG_PAGE, "lfs_putpages: again: looping, n = %d\n", debug_n_again));
825*0a6a1f1dSLionel Sambuc #endif
826*0a6a1f1dSLionel Sambuc
827*0a6a1f1dSLionel Sambuc KASSERT(sp != NULL && sp->vp == vp);
828*0a6a1f1dSLionel Sambuc if (!seglocked && !donewriting) {
829*0a6a1f1dSLionel Sambuc sp->vp = NULL;
830*0a6a1f1dSLionel Sambuc
831*0a6a1f1dSLionel Sambuc /* Write indirect blocks as well */
832*0a6a1f1dSLionel Sambuc lfs_gather(fs, fs->lfs_sp, vp, lfs_match_indir);
833*0a6a1f1dSLionel Sambuc lfs_gather(fs, fs->lfs_sp, vp, lfs_match_dindir);
834*0a6a1f1dSLionel Sambuc lfs_gather(fs, fs->lfs_sp, vp, lfs_match_tindir);
835*0a6a1f1dSLionel Sambuc
836*0a6a1f1dSLionel Sambuc KASSERT(sp->vp == NULL);
837*0a6a1f1dSLionel Sambuc sp->vp = vp;
838*0a6a1f1dSLionel Sambuc }
839*0a6a1f1dSLionel Sambuc
840*0a6a1f1dSLionel Sambuc /*
841*0a6a1f1dSLionel Sambuc * Blocks are now gathered into a segment waiting to be written.
842*0a6a1f1dSLionel Sambuc * All that's left to do is update metadata, and write them.
843*0a6a1f1dSLionel Sambuc */
844*0a6a1f1dSLionel Sambuc lfs_updatemeta(sp);
845*0a6a1f1dSLionel Sambuc KASSERT(sp->vp == vp);
846*0a6a1f1dSLionel Sambuc sp->vp = NULL;
847*0a6a1f1dSLionel Sambuc
848*0a6a1f1dSLionel Sambuc /*
849*0a6a1f1dSLionel Sambuc * If we were called from lfs_writefile, we don't need to clean up
850*0a6a1f1dSLionel Sambuc * the FIP or unlock the segment lock. We're done.
851*0a6a1f1dSLionel Sambuc */
852*0a6a1f1dSLionel Sambuc if (seglocked) {
853*0a6a1f1dSLionel Sambuc KASSERT(!mutex_owned(vp->v_interlock));
854*0a6a1f1dSLionel Sambuc return error;
855*0a6a1f1dSLionel Sambuc }
856*0a6a1f1dSLionel Sambuc
857*0a6a1f1dSLionel Sambuc /* Clean up FIP and send it to disk. */
858*0a6a1f1dSLionel Sambuc lfs_release_finfo(fs);
859*0a6a1f1dSLionel Sambuc lfs_writeseg(fs, fs->lfs_sp);
860*0a6a1f1dSLionel Sambuc
861*0a6a1f1dSLionel Sambuc /*
862*0a6a1f1dSLionel Sambuc * Remove us from paging queue if we wrote all our pages.
863*0a6a1f1dSLionel Sambuc */
864*0a6a1f1dSLionel Sambuc if (origendoffset == 0 || ap->a_flags & PGO_ALLPAGES) {
865*0a6a1f1dSLionel Sambuc mutex_enter(&lfs_lock);
866*0a6a1f1dSLionel Sambuc if (ip->i_flags & IN_PAGING) {
867*0a6a1f1dSLionel Sambuc ip->i_flags &= ~IN_PAGING;
868*0a6a1f1dSLionel Sambuc TAILQ_REMOVE(&fs->lfs_pchainhd, ip, i_lfs_pchain);
869*0a6a1f1dSLionel Sambuc }
870*0a6a1f1dSLionel Sambuc mutex_exit(&lfs_lock);
871*0a6a1f1dSLionel Sambuc }
872*0a6a1f1dSLionel Sambuc
873*0a6a1f1dSLionel Sambuc /*
874*0a6a1f1dSLionel Sambuc * XXX - with the malloc/copy writeseg, the pages are freed by now
875*0a6a1f1dSLionel Sambuc * even if we don't wait (e.g. if we hold a nested lock). This
876*0a6a1f1dSLionel Sambuc * will not be true if we stop using malloc/copy.
877*0a6a1f1dSLionel Sambuc */
878*0a6a1f1dSLionel Sambuc KASSERT(fs->lfs_sp->seg_flags & SEGM_PROT);
879*0a6a1f1dSLionel Sambuc lfs_segunlock(fs);
880*0a6a1f1dSLionel Sambuc
881*0a6a1f1dSLionel Sambuc /*
882*0a6a1f1dSLionel Sambuc * Wait for v_numoutput to drop to zero. The seglock should
883*0a6a1f1dSLionel Sambuc * take care of this, but there is a slight possibility that
884*0a6a1f1dSLionel Sambuc * aiodoned might not have got around to our buffers yet.
885*0a6a1f1dSLionel Sambuc */
886*0a6a1f1dSLionel Sambuc if (sync) {
887*0a6a1f1dSLionel Sambuc mutex_enter(vp->v_interlock);
888*0a6a1f1dSLionel Sambuc while (vp->v_numoutput > 0) {
889*0a6a1f1dSLionel Sambuc DLOG((DLOG_PAGE, "lfs_putpages: ino %d sleeping on"
890*0a6a1f1dSLionel Sambuc " num %d\n", ip->i_number, vp->v_numoutput));
891*0a6a1f1dSLionel Sambuc cv_wait(&vp->v_cv, vp->v_interlock);
892*0a6a1f1dSLionel Sambuc }
893*0a6a1f1dSLionel Sambuc mutex_exit(vp->v_interlock);
894*0a6a1f1dSLionel Sambuc }
895*0a6a1f1dSLionel Sambuc KASSERT(!mutex_owned(vp->v_interlock));
896*0a6a1f1dSLionel Sambuc return error;
897*0a6a1f1dSLionel Sambuc }
898*0a6a1f1dSLionel Sambuc
899