PATCH [2.4.0test10]: Kiobuf#03, add unmap/dirty-page map-specific kiobuf functions
Subsystems (4)
Hi,
OK, this is the bit which addresses the dirtying of pages mapped into a kiobuf.
It adds mapping-specific info to the kiobuf, so that just as map_user_kiobuf can add the file struct vector to allow any necessary writepage after the IO completes, so can other mapping functions specify their own operations on the mapped pages to deal with IO completion.
The patch adds a "map_private" field in the kiobuf to be used by the mapping function's callbacks, and a vector of callbacks currently containing:
mark_dirty:
marks all pages mapped in the kiobuf as dirty. Used by the raw device code after read IOs complete to propagate the dirty state into any mmaped files.
unmap:
allows for cleanup of the map_private field when the kiobuf is destroyed.
map_user_kiobuf does nothing special for kiobufs marked for write (meaning IO writes, ie. reads from memory), but sets up map_private as a vector of struct file *s for read IOs. The mark_dirty callback propagates that info into the page if page->mapping->a_ops->writepage exists.
If the writepage does not exist, then it should simply do a SetPageDirty on the page, but the VM cannot cope with this at present:
the swapout code does not yet handle flushing of dirty pages during page eviction, and if a process with such a page mapped exits, __free_pages_ok() will bugcheck on seeing the dirty bit.
Rik, you said you were going to look at deferred swapout using the page dirty flag for anonymous pages --- do you want to take this up?
One other thing: at some point in the future I'd like to add a "mark_dirty" a_ops callback to be used in preference of the writepage. This would allow filesystems such as ext2, which don't require the struct file * for page writes, to defer the write of these mmaped pages until later rather than to force a flush to disk every time we dirty a kiobuf-mapped mmaped page.
Cheers,
Stephen
drivers/char/raw.c +3 -0
@@ -326,6 +326,9 @@ size -= iobuf->retval; buf += iobuf->retval; } + +if (rw ==READ ) +mark_dirty_kiovec (&iobuf,1 , iobuf->retval);unmap_kiobuf (iobuf);/* The unlock_kiobuf is implicit here */
fs/iobuf.c +37 -1
@@ -128,6 +128,7 @@ } +/* * Unmap all of the pages referenced by a kiobuf. We release the pages, * and unlock them if they were locked.
@@ -137,6 +138,10 @@ {int i;struct page *map; + +if (iobuf->map_ops && iobuf->map_ops->unmap) + iobuf->map_ops->unmap (iobuf); + iobuf->map_ops =NULL ;for (i =0 ; i < iobuf->nr_pages; i++) { map = iobuf->maplist[i];
@@ -151,6 +156,38 @@ iobuf->locked =0 ; } +void unmap_kiovec (struct kiobuf **iovec,int nr) +{ +for (; nr >0 ; --nr) +unmap_kiobuf (*iovec++); +} + +/* Mark all kiobufs in a vector as dirty, propagating dirty bits to all +pages in the vector. "bytes" indicates how much of the data has been +modified. A value less than zero means "everything". */ + +int mark_dirty_kiovec (struct kiobuf **iovec,int nr,int bytes) +{ +struct kiobuf *iobuf; +int buf_bytes; +int rc, err =0 ; + +for (; nr >0 ; --nr) { + iobuf = *iovec++; + buf_bytes = bytes; +if (buf_bytes <0 || buf_bytes > iobuf->length) + buf_bytes = iobuf->length; + rc = iobuf->map_ops->mark_dirty (iobuf, bytes); +if (rc && !err) + err = rc; +if (bytes >=0 ) + bytes -= buf_bytes; +if (!bytes) +break ; + } +return err; +} +/* * Lock down all of the pages of a kiovec for IO.
@@ -253,5 +290,4 @@ }return 0 ; } -
include/linux/iobuf.h +15 -0
@@ -29,6 +29,15 @@#define KIO_STATIC_PAGES (KIO_MAX_ATOMIC_IO / (PAGE_SIZE >> 10) + 1)#define KIO_MAX_SECTORS (KIO_MAX_ATOMIC_IO * 2) +struct kiobuf ; + +/* Operations on an established mapping of a kiobuf */ +struct kiobuf_map_operations +{ +int (*unmap) (struct kiobuf *); +int (*mark_dirty) (struct kiobuf *,int ); +}; +/* The main kiobuf struct used for all our IO! */ struct kiobuf
@@ -60,6 +69,11 @@void (*end_io) (struct kiobuf *);/* Completion callback */ wait_queue_head_t wait_queue; + +/* Private state for the mapping function: allows arbitrary IO +routines to perform completion appropriately. */ +void * map_private; +struct kiobuf_map_operations * map_ops; };
@@ -80,6 +94,7 @@void unmap_kiobuf (struct kiobuf *iobuf);int lock_kiovec (int nr,struct kiobuf *iovec[],int wait);int unlock_kiovec (int nr,struct kiobuf *iovec[]); +int mark_dirty_kiovec (struct kiobuf **iovec,int nr,int bytes);/* fs/buffer.c */
mm/memory.c +117 -3
166 lines not on this page · raw message