Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 28 Sep 1998 23:18:01 +0000 (GMT)
From:      Terry Lambert <tlambert@primenet.com>
To:        tlambert@primenet.com (Terry Lambert)
Cc:        dg@root.com, tlambert@primenet.com, current@FreeBSD.ORG
Subject:   Re: VM mmap file extension bug still exists?
Message-ID:  <199809282318.QAA11434@usr04.primenet.com>
In-Reply-To: <199809280631.XAA22753@usr07.primenet.com> from "Terry Lambert" at Sep 28, 98 06:31:55 am

next in thread | previous in thread | raw e-mail | index | archive | help
> > >I don't think this was committed?
> > 
> >    No, it wasn't. I think the change is wrong, but I need to look more
> > carefully at it to be sure. If it does anything at all, it probably only
> > narrows the problem, making it even more difficult to find and fix in the
> > future. I don't think your other proposed solution is correct, either, but
> > I'm not ready to say that with any confidence.


Here is my analysis.  Let me know if you need more information.


Actually, look at the usage of vnp_size to see why having a larger than
valid value is BAD(tm).


vnode_pager_input_old:

	if (IDX_TO_OFF(m->pindex) >= object->un_pager.vnp.vnp_size) {
		return VM_PAGER_BAD;
	} else {

vnode_pager_haspage:

        /*      
         * If filesystem no longer mounted or offset beyond end of file we do
         * not have the page.
         */      
        if ((vp->v_mount == NULL) ||
                (IDX_TO_OFF(pindex) >= object->un_pager.vnp.vnp_size))
                return FALSE;


/*      
 * Lets the VM system know about a change in size for a file.
 * We adjust our own internal size and flush any cached pages in
 * the associated object that are affected by the size change.
 *      
 * Note: this routine may be invoked as a result of a pager put
 * operation (possibly at object termination time), so we must be careful.
 */     
vnode_pager_setsize:

        /*      
         * Hasn't changed size  
         */     
        if (nsize == object->un_pager.vnp.vnp_size)
                return; 

        /*      
         * File has shrunk. Toss any cached pages beyond the new EOF.
         */
        if (nsize < object->un_pager.vnp.vnp_size) {
                vm_ooffset_t nsizerounded;
                nsizerounded = IDX_TO_OFF(OFF_TO_IDX(nsize + PAGE_MASK));
                if (nsizerounded < object->un_pager.vnp.vnp_size) {
                        vm_pindex_t st, end;
                        st = OFF_TO_IDX(nsize + PAGE_MASK);
                        end = OFF_TO_IDX(object->un_pager.vnp.vnp_size);

                        vm_freeze_copyopts(object, OFF_TO_IDX(nsize), object->si
ze);    
                        vm_object_page_remove(object, st, end, FALSE);
                }       
                /*
                 * this gets rid of garbage at the end of a page that is now
                 * only partially backed by the vnode...
                 */     
                if (nsize & PAGE_MASK) {
                        vm_offset_t kva;
                        vm_page_t m;

                        m = vm_page_lookup(object, OFF_TO_IDX(nsize));
                        if (m) {
                                kva = vm_pager_map_page(m);
                                bzero((caddr_t) kva + (nsize & PAGE_MASK),
                                    (int) (round_page(nsize) - nsize));
                                vm_pager_unmap_page(kva);
                        }
                }
        }
        object->un_pager.vnp.vnp_size = nsize;
        object->size = OFF_TO_IDX(nsize + PAGE_MASK);



That is, without the patch the following failures can occur:

o	mmap() on FS's that use vnode_pager_input_old (CODA, etc.)

o	vnode_pager_haspage will not fail on an offset past EOF,
	even though it should.

o	A file extension of a file shorter than a page boundary
	to a new length still shorter than a page will result in
	all of the "if (nsize < object->un_pager.vnp.vnp_size) {"
	code being skipped in vnode_pager_setsize, but the vnp_size
	will be updated, possibly exposing code.

o	A file extension to exactly a page boundary will skip all
	the code.

o	If the last block in the file is on a frag, then you will
	overwrite adjacent frags, if the last page gets dirtied.

o	If the last page is the last frag and the last block of the
	file is in that frag, then you will overwrite the start of
	adjacent blocks, if the last page gets dirtied.


					Terry Lambert
					terry@lambert.org
---
Any opinions in this posting are my own and not those of my present
or previous employers.

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199809282318.QAA11434>