Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 137434
b: refs/heads/master
c: 3297e76
h: refs/heads/master
v: v3
  • Loading branch information
Nicolas Pitre committed Mar 16, 2009
1 parent fb56b20 commit add8e0d
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 9 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3835f6cb645bdb9a58aa6e062fe1d5777f1a9748
refs/heads/master: 3297e760776af18a26bf30046cbaaae2e730c5c2
65 changes: 57 additions & 8 deletions trunk/mm/highmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,25 @@ pte_t * pkmap_page_table;

static DECLARE_WAIT_QUEUE_HEAD(pkmap_map_wait);

/*
* Most architectures have no use for kmap_high_get(), so let's abstract
* the disabling of IRQ out of the locking in that case to save on a
* potential useless overhead.
*/
#ifdef ARCH_NEEDS_KMAP_HIGH_GET
#define lock_kmap() spin_lock_irq(&kmap_lock)
#define unlock_kmap() spin_unlock_irq(&kmap_lock)
#define lock_kmap_any(flags) spin_lock_irqsave(&kmap_lock, flags)
#define unlock_kmap_any(flags) spin_unlock_irqrestore(&kmap_lock, flags)
#else
#define lock_kmap() spin_lock(&kmap_lock)
#define unlock_kmap() spin_unlock(&kmap_lock)
#define lock_kmap_any(flags) \
do { spin_lock(&kmap_lock); (void)(flags); } while (0)
#define unlock_kmap_any(flags) \
do { spin_unlock(&kmap_lock); (void)(flags); } while (0)
#endif

static void flush_all_zero_pkmaps(void)
{
int i;
Expand Down Expand Up @@ -113,9 +132,9 @@ static void flush_all_zero_pkmaps(void)
*/
void kmap_flush_unused(void)
{
spin_lock(&kmap_lock);
lock_kmap();
flush_all_zero_pkmaps();
spin_unlock(&kmap_lock);
unlock_kmap();
}

static inline unsigned long map_new_virtual(struct page *page)
Expand Down Expand Up @@ -145,10 +164,10 @@ static inline unsigned long map_new_virtual(struct page *page)

__set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&pkmap_map_wait, &wait);
spin_unlock(&kmap_lock);
unlock_kmap();
schedule();
remove_wait_queue(&pkmap_map_wait, &wait);
spin_lock(&kmap_lock);
lock_kmap();

/* Somebody else might have mapped it while we slept */
if (page_address(page))
Expand Down Expand Up @@ -184,29 +203,59 @@ void *kmap_high(struct page *page)
* For highmem pages, we can't trust "virtual" until
* after we have the lock.
*/
spin_lock(&kmap_lock);
lock_kmap();
vaddr = (unsigned long)page_address(page);
if (!vaddr)
vaddr = map_new_virtual(page);
pkmap_count[PKMAP_NR(vaddr)]++;
BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 2);
spin_unlock(&kmap_lock);
unlock_kmap();
return (void*) vaddr;
}

EXPORT_SYMBOL(kmap_high);

#ifdef ARCH_NEEDS_KMAP_HIGH_GET
/**
* kmap_high_get - pin a highmem page into memory
* @page: &struct page to pin
*
* Returns the page's current virtual memory address, or NULL if no mapping
* exists. When and only when a non null address is returned then a
* matching call to kunmap_high() is necessary.
*
* This can be called from any context.
*/
void *kmap_high_get(struct page *page)
{
unsigned long vaddr, flags;

lock_kmap_any(flags);
vaddr = (unsigned long)page_address(page);
if (vaddr) {
BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 1);
pkmap_count[PKMAP_NR(vaddr)]++;
}
unlock_kmap_any(flags);
return (void*) vaddr;
}
#endif

/**
* kunmap_high - map a highmem page into memory
* @page: &struct page to unmap
*
* If ARCH_NEEDS_KMAP_HIGH_GET is not defined then this may be called
* only from user context.
*/
void kunmap_high(struct page *page)
{
unsigned long vaddr;
unsigned long nr;
unsigned long flags;
int need_wakeup;

spin_lock(&kmap_lock);
lock_kmap_any(flags);
vaddr = (unsigned long)page_address(page);
BUG_ON(!vaddr);
nr = PKMAP_NR(vaddr);
Expand All @@ -232,7 +281,7 @@ void kunmap_high(struct page *page)
*/
need_wakeup = waitqueue_active(&pkmap_map_wait);
}
spin_unlock(&kmap_lock);
unlock_kmap_any(flags);

/* do wake-up, if needed, race-free outside of the spin lock */
if (need_wakeup)
Expand Down

0 comments on commit add8e0d

Please sign in to comment.