Skip to content

Commit

Permalink
mm: add support for direct_IO to highmem pages
Browse files Browse the repository at this point in the history
The patch "mm: add support for a filesystem to activate swap files and use
direct_IO for writing swap pages" added support for using direct_IO to
write swap pages but it is insufficient for highmem pages.

To support highmem pages, this patch kmaps() the page before calling the
direct_IO() handler.  As direct_IO deals with virtual addresses an
additional helper is necessary for get_kernel_pages() to lookup the struct
page for a kmap virtual address.

Signed-off-by: Mel Gorman <[email protected]>
Acked-by: Rik van Riel <[email protected]>
Cc: Christoph Hellwig <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Eric B Munson <[email protected]>
Cc: Eric Paris <[email protected]>
Cc: James Morris <[email protected]>
Cc: Mel Gorman <[email protected]>
Cc: Mike Christie <[email protected]>
Cc: Neil Brown <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Sebastian Andrzej Siewior <[email protected]>
Cc: Trond Myklebust <[email protected]>
Cc: Xiaotian Feng <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Mel Gorman authored and torvalds committed Aug 1, 2012
1 parent a509bc1 commit 5a17811
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 3 deletions.
7 changes: 7 additions & 0 deletions include/linux/highmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,17 @@ extern unsigned long totalhigh_pages;

void kmap_flush_unused(void);

struct page *kmap_to_page(void *addr);

#else /* CONFIG_HIGHMEM */

static inline unsigned int nr_free_highpages(void) { return 0; }

static inline struct page *kmap_to_page(void *addr)
{
return virt_to_page(addr);
}

#define totalhigh_pages 0UL

#ifndef ARCH_HAS_KMAP
Expand Down
12 changes: 12 additions & 0 deletions mm/highmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,18 @@ static DECLARE_WAIT_QUEUE_HEAD(pkmap_map_wait);
do { spin_unlock(&kmap_lock); (void)(flags); } while (0)
#endif

struct page *kmap_to_page(void *vaddr)
{
unsigned long addr = (unsigned long)vaddr;

if (addr >= PKMAP_ADDR(0) && addr <= PKMAP_ADDR(LAST_PKMAP)) {
int i = (addr - PKMAP_ADDR(0)) >> PAGE_SHIFT;
return pte_page(pkmap_page_table[i]);
}

return virt_to_page(addr);
}

static void flush_all_zero_pkmaps(void)
{
int i;
Expand Down
3 changes: 2 additions & 1 deletion mm/page_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
struct file *swap_file = sis->swap_file;
struct address_space *mapping = swap_file->f_mapping;
struct iovec iov = {
.iov_base = page_address(page),
.iov_base = kmap(page),
.iov_len = PAGE_SIZE,
};

Expand All @@ -218,6 +218,7 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
ret = mapping->a_ops->direct_IO(KERNEL_WRITE,
&kiocb, &iov,
kiocb.ki_pos, 1);
kunmap(page);
if (ret == PAGE_SIZE) {
count_vm_event(PSWPOUT);
ret = 0;
Expand Down
3 changes: 1 addition & 2 deletions mm/swap.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,7 @@ int get_kernel_pages(const struct kvec *kiov, int nr_segs, int write,
if (WARN_ON(kiov[seg].iov_len != PAGE_SIZE))
return seg;

/* virt_to_page sanity checks the PFN */
pages[seg] = virt_to_page(kiov[seg].iov_base);
pages[seg] = kmap_to_page(kiov[seg].iov_base);
page_cache_get(pages[seg]);
}

Expand Down

0 comments on commit 5a17811

Please sign in to comment.