int mpage_writepages (struct address_space * mapping, struct writeback_control * wbc, get_block_t get_block);
This is a library function, which implements the writepages address_space_operation.
(The next two paragraphs refer to code which isn't here yet, but they explain the presence of address_space.io_pages)
Pages can be moved from clean_pages or locked_pages onto dirty_pages at any time - it's not possible to lock against that. So pages which have already been added to a BIO may magically reappear on the dirty_pages list. And mpage_writepages will again try to lock those pages. But I/O has not yet been started against the page. Thus deadlock.
To avoid this, mpage_writepages will only write pages from io_pages. The caller must place them there. We walk io_pages, locking the pages and submitting them for I/O, moving them to locked_pages.
This has the added benefit of preventing a livelock which would otherwise occur if pages are being dirtied faster than we can write them out.
If a page is already under I/O, generic_writepages skips it, even if it's dirty. This is desirable behaviour for memory-cleaning writeback, but it is INCORRECT for data-integrity system calls such as fsync. fsync and msync need to guarantee that all the data which was dirty at the time the call was made get new I/O started against them. So if called_for_sync is true, we must wait for existing IO to complete.
It's fairly rare for PageWriteback pages to be on ->dirty_pages. It means that someone redirtied the page while it was under I/O.
This is a library function, which implements the writepages address_space_operation.
(The next two paragraphs refer to code which isn't here yet, but they explain the presence of address_space.io_pages)
Pages can be moved from clean_pages or locked_pages onto dirty_pages at any time - it's not possible to lock against that. So pages which have already been added to a BIO may magically reappear on the dirty_pages list. And mpage_writepages will again try to lock those pages. But I/O has not yet been started against the page. Thus deadlock.
To avoid this, mpage_writepages will only write pages from io_pages. The caller must place them there. We walk io_pages, locking the pages and submitting them for I/O, moving them to locked_pages.
This has the added benefit of preventing a livelock which would otherwise occur if pages are being dirtied faster than we can write them out.
If a page is already under I/O, generic_writepages skips it, even if it's dirty. This is desirable behaviour for memory-cleaning writeback, but it is INCORRECT for data-integrity system calls such as fsync. fsync and msync need to guarantee that all the data which was dirty at the time the call was made get new I/O started against them. So if called_for_sync is true, we must wait for existing IO to complete.
It's fairly rare for PageWriteback pages to be on ->dirty_pages. It means that someone redirtied the page while it was under I/O.