diff -urNp --exclude CVS --exclude BitKeeper --exclude {arch} --exclude .arch-ids x-ref/mm/memory.c x/mm/memory.c --- x-ref/mm/memory.c 2004-05-31 12:49:48.952993264 +0200 +++ x/mm/memory.c 2004-05-31 12:50:50.205681440 +0200 @@ -576,17 +576,24 @@ int map_user_kiobuf(int rw, struct kiobu err = get_user_pages(current, mm, va, pgcount, (rw==READ), 0, iobuf->maplist, NULL); up_read(&mm->mmap_sem); - if (err < 0) { + /* get_user_pages returns the amount of mapped pages, + * which can be less than the amount of requested pages + * in some cases. To avoid surprises downstream, we + * unmap and return an error in those cases. -bjornw + */ + if(err > 0) + iobuf->nr_pages = err; + if (err < pgcount) { + /* unmap depends on nr_pages being set at this point */ unmap_kiobuf(iobuf); dprintk ("map_user_kiobuf: end %d\n", err); - return err; + return err < 0 ? err : -ENOMEM; } - iobuf->nr_pages = err; - while (pgcount--) { + while (err--) { /* FIXME: flush superflous for rw==READ, * probably wrong function for rw==WRITE */ - flush_dcache_page(iobuf->maplist[pgcount]); + flush_dcache_page(iobuf->maplist[err]); } dprintk ("map_user_kiobuf: end OK\n"); return 0;