for (i = 0; i < npages2; i++) { pgs2[i]->flags &= ~PG_RDONLY; }
ufs_balloc_range(vp, off, len, cred, flags)	struct vnode *vp;	off_t off, len;	struct ucred *cred;	int flags;{	off_t oldeof, neweof, oldeob, neweob, oldpagestart, pagestart;	struct uvm_object *uobj;	int i, delta, error, npages1, npages2;	int bshift = vp->v_mount->mnt_fs_bshift;	int bsize = 1 << bshift;	int ppb = MAX(bsize >> PAGE_SHIFT, 1);	struct vm_page *pgs1[ppb], *pgs2[ppb];	UVMHIST_FUNC("ufs_balloc_range"); UVMHIST_CALLED(ubchist);	UVMHIST_LOG(ubchist, "vp %p off 0x%x len 0x%x u_size 0x%x",		    vp, off, len, vp->v_uvm.u_size);	oldeof = vp->v_uvm.u_size;	error = VOP_SIZE(vp, oldeof, &oldeob);	if (error) {		return error;	}	neweof = MAX(vp->v_uvm.u_size, off + len);	error = VOP_SIZE(vp, neweof, &neweob);	if (error) {		return error;	}	error = 0;	uobj = &vp->v_uvm.u_obj;	pgs1[0] = pgs2[0] = NULL;	/*	 * if the last block in the file is not a full block (ie. it is a	 * fragment), and this allocation is causing the fragment to change	 * size (either to expand the fragment or promote it to a full block),	 * cache the old last block (at its new size).	 */	oldpagestart = trunc_page(oldeof) & ~(bsize - 1);	if ((oldeob & (bsize - 1)) != 0 && oldeob != neweob) {		npages1 = MIN(ppb, (round_page(neweob) - oldpagestart) >>			      PAGE_SHIFT);		memset(pgs1, 0, npages1 * sizeof(struct vm_page *));		simple_lock(&uobj->vmobjlock);		error = VOP_GETPAGES(vp, oldpagestart, pgs1, &npages1,		    0, VM_PROT_READ, 0, PGO_SYNCIO|PGO_PASTEOF);		if (error) {			goto out;		}		simple_lock(&uobj->vmobjlock);		uvm_lock_pageq();		for (i = 0; i < npages1; i++) {			UVMHIST_LOG(ubchist, "got pgs1[%d] %p", i, pgs1[i],0,0);			KASSERT((pgs1[i]->flags & PG_RELEASED) == 0);			pgs1[i]->flags &= ~PG_CLEAN;			uvm_pageactivate(pgs1[i]);		}		uvm_unlock_pageq();		simple_unlock(&uobj->vmobjlock);	}	/*	 * cache the new range as well.  this will create zeroed pages	 * where the new block will be and keep them locked until the	 * new block is allocated, so there will be no window where	 * the old contents of the new block is visible to racing threads.	 */	pagestart = trunc_page(off) & ~(bsize - 1);	if (pagestart != oldpagestart || pgs1[0] == NULL) {		npages2 = MIN(ppb, (round_page(neweob) - pagestart) >>			      PAGE_SHIFT);		memset(pgs2, 0, npages2 * sizeof(struct vm_page *));		simple_lock(&uobj->vmobjlock);		error = VOP_GETPAGES(vp, pagestart, pgs2, &npages2, 0,		    VM_PROT_READ, 0, PGO_SYNCIO|PGO_PASTEOF);		if (error) {			goto out;		}		simple_lock(&uobj->vmobjlock);		uvm_lock_pageq();		for (i = 0; i < npages2; i++) {			UVMHIST_LOG(ubchist, "got pgs2[%d] %p", i, pgs2[i],0,0);			KASSERT((pgs2[i]->flags & PG_RELEASED) == 0);			pgs2[i]->flags &= ~PG_CLEAN;			uvm_pageactivate(pgs2[i]);		}		uvm_unlock_pageq();		simple_unlock(&uobj->vmobjlock);	}	/*	 * adjust off to be block-aligned.	 */	delta = off & (bsize - 1);	off -= delta;	len += delta;	/*	 * now allocate the range.	 */	lockmgr(&vp->v_glock, LK_EXCLUSIVE, NULL, curproc);	error = VOP_BALLOCN(vp, off, len, cred, flags);	lockmgr(&vp->v_glock, LK_RELEASE, NULL, curproc);	/*	 * unbusy any pages we are holding.	 * if we got an error, free any pages we created past the old eob.	 */out:	simple_lock(&uobj->vmobjlock);	if (error) {		(void) (uobj->pgops->pgo_flush)(uobj, round_page(oldeob), 0,		    PGO_FREE);	}	if (pgs1[0] != NULL) {		uvm_page_unbusy(pgs1, npages1);		/*		 * The data in the frag might be moving to a new disk location.		 * We need to flush pages to the new disk locations.		 */		(uobj->pgops->pgo_flush)(uobj, oldeof & ~(bsize - 1),		    MIN((oldeof + bsize) & ~(bsize - 1), neweof),		    PGO_CLEANIT | ((flags & B_SYNC) ? PGO_SYNCIO : 0));	}	if (pgs2[0] != NULL) {		uvm_page_unbusy(pgs2, npages2);	}	simple_unlock(&uobj->vmobjlock);	return error;}