From: NIIBE Y. <gn...@m1...> - 2002-03-20 01:50:43
|
Sync up to 2.5.5 (getting changes from patch-2.5.5.bz2). I add the change for your reference. Please note that it's note me who does this change, I just incorporate the change into the repository. 2002-03-20 NIIBE Yutaka <gn...@m1...> Update to 2.5.5. * AGAINST-2.5.5: New file. * AGAINST-2.5.4: Removed. * Documentation/cachetlb.txt: Include the change. * Makefile: Version 2.5.4. Merged. * arch/sh/config.in, drivers/Makefile: Sound driver move. * arch/sh/kernel/signal.c: recalc_sigpending API change. * drivers/net/8139too.c, drivers/net/Config.in: Update. * drivers/pci/pci.ids: Update. * include/asm-sh/pgtable.h: New API flush_icache_user_range, Removed page_address API here (move to linux/mm.h). * include/net/inet_ecn.h: Update. * kernel/ptrace.c: Use new API flush_icache_user_range. * mm/memory.c: Update. Index: Makefile =================================================================== RCS file: /cvsroot/linuxsh/linux/Makefile,v retrieving revision 1.9 diff -u -3 -p -r1.9 Makefile --- Makefile 1 Mar 2002 05:08:25 -0000 1.9 +++ Makefile 20 Mar 2002 01:46:38 -0000 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 5 -SUBLEVEL = 4 +SUBLEVEL = 5 EXTRAVERSION = -sh KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -122,7 +122,7 @@ CORE_FILES =kernel/kernel.o mm/mm.o fs/f NETWORKS =net/network.o LIBS =$(TOPDIR)/lib/lib.a -SUBDIRS =kernel drivers mm fs net ipc lib +SUBDIRS =kernel lib drivers mm fs net ipc sound DRIVERS-n := DRIVERS-y := @@ -156,7 +156,7 @@ ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_B DRIVERS-y += drivers/cdrom/driver.o endif -DRIVERS-$(CONFIG_SOUND) += drivers/sound/sounddrivers.o +DRIVERS-$(CONFIG_SOUND) += sound/sound.o DRIVERS-$(CONFIG_PCI) += drivers/pci/driver.o DRIVERS-$(CONFIG_MTD) += drivers/mtd/mtdlink.o DRIVERS-$(CONFIG_PCMCIA) += drivers/pcmcia/pcmcia.o @@ -202,7 +202,7 @@ CLEAN_FILES = \ drivers/char/drm/*-mod.c \ drivers/pci/devlist.h drivers/pci/classlist.h drivers/pci/gen-devlist \ drivers/zorro/devlist.h drivers/zorro/gen-devlist \ - drivers/sound/bin2hex drivers/sound/hex2hex \ + sound/oss/bin2hex sound/oss/hex2hex \ drivers/atm/fore200e_mkfirm drivers/atm/{pca,sba}*{.bin,.bin1,.bin2} \ drivers/scsi/aic7xxx/aicasm/aicasm_gram.c \ drivers/scsi/aic7xxx/aicasm/aicasm_scan.c \ @@ -223,11 +223,11 @@ MRPROPER_FILES = \ drivers/net/hamradio/soundmodem/sm_tbl_{hapn4800,psk4800}.h \ drivers/net/hamradio/soundmodem/sm_tbl_{afsk2400_7,afsk2400_8}.h \ drivers/net/hamradio/soundmodem/gentbl \ - drivers/sound/*_boot.h drivers/sound/.*.boot \ - drivers/sound/msndinit.c \ - drivers/sound/msndperm.c \ - drivers/sound/pndsperm.c \ - drivers/sound/pndspini.c \ + sound/oss/*_boot.h sound/oss/.*.boot \ + sound/oss/msndinit.c \ + sound/oss/msndperm.c \ + sound/oss/pndsperm.c \ + sound/oss/pndspini.c \ drivers/atm/fore200e_*_fw.c drivers/atm/.fore200e_*.fw \ .version .config* config.in config.old \ scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp \ @@ -344,7 +344,7 @@ init/main.o: init/main.c include/config/ init/do_mounts.o: init/do_mounts.c include/config/MARKER $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -c -o $*.o $< -fs lib mm ipc kernel drivers net: dummy +fs lib mm ipc kernel drivers net sound: dummy $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@) TAGS: dummy Index: Documentation/cachetlb.txt =================================================================== RCS file: /cvsroot/linuxsh/linux/Documentation/cachetlb.txt,v retrieving revision 1.3 diff -u -3 -p -r1.3 cachetlb.txt --- Documentation/cachetlb.txt 24 Jan 2002 11:04:15 -0000 1.3 +++ Documentation/cachetlb.txt 20 Mar 2002 01:46:38 -0000 @@ -341,6 +341,17 @@ Here is the new interface: If the icache does not snoop stores then this routine will need to flush it. + void flush_icache_user_range(struct vm_area_struct *vma, + struct page *page, unsigned long addr, int len) + This is called when the kernel stores into addresses that are + part of the address space of a user process (which may be some + other process than the current process). The addr argument + gives the virtual address in that process's address space, + page is the page which is being modified, and len indicates + how many bytes have been modified. The modified region must + not cross a page boundary. Currently this is only called from + kernel/ptrace.c. + void flush_icache_page(struct vm_area_struct *vma, struct page *page) All the functionality of flush_icache_page can be implemented in flush_dcache_page and update_mmu_cache. In 2.5 the hope is to Index: arch/sh/config.in =================================================================== RCS file: /cvsroot/linuxsh/linux/arch/sh/config.in,v retrieving revision 1.5 diff -u -3 -p -r1.5 config.in --- arch/sh/config.in 19 Mar 2002 23:48:05 -0000 1.5 +++ arch/sh/config.in 20 Mar 2002 01:46:38 -0000 @@ -356,7 +356,7 @@ comment 'Sound' tristate 'Sound card support' CONFIG_SOUND if [ "$CONFIG_SOUND" != "n" ]; then - source drivers/sound/Config.in + source sound/Config.in fi endmenu Index: arch/sh/kernel/signal.c =================================================================== RCS file: /cvsroot/linuxsh/linux/arch/sh/kernel/signal.c,v retrieving revision 1.3 diff -u -3 -p -r1.3 signal.c --- arch/sh/kernel/signal.c 1 Mar 2002 01:55:10 -0000 1.3 +++ arch/sh/kernel/signal.c 20 Mar 2002 01:46:38 -0000 @@ -83,7 +83,7 @@ sys_sigsuspend(old_sigset_t mask, spin_lock_irq(¤t->sigmask_lock); saveset = current->blocked; siginitset(¤t->blocked, mask); - recalc_sigpending(current); + recalc_sigpending(); spin_unlock_irq(¤t->sigmask_lock); regs.regs[0] = -EINTR; @@ -112,7 +112,7 @@ sys_rt_sigsuspend(sigset_t *unewset, siz spin_lock_irq(¤t->sigmask_lock); saveset = current->blocked; current->blocked = newset; - recalc_sigpending(current); + recalc_sigpending(); spin_unlock_irq(¤t->sigmask_lock); regs.regs[0] = -EINTR; @@ -283,7 +283,7 @@ asmlinkage int sys_sigreturn(unsigned lo spin_lock_irq(¤t->sigmask_lock); current->blocked = set; - recalc_sigpending(current); + recalc_sigpending(); spin_unlock_irq(¤t->sigmask_lock); if (restore_sigcontext(®s, &frame->sc, &r0)) @@ -313,7 +313,7 @@ asmlinkage int sys_rt_sigreturn(unsigned sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); current->blocked = set; - recalc_sigpending(current); + recalc_sigpending(); spin_unlock_irq(¤t->sigmask_lock); if (restore_sigcontext(®s, &frame->uc.uc_mcontext, &r0)) @@ -558,7 +558,7 @@ handle_signal(unsigned long sig, struct spin_lock_irq(¤t->sigmask_lock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); sigaddset(¤t->blocked,sig); - recalc_sigpending(current); + recalc_sigpending(); spin_unlock_irq(¤t->sigmask_lock); } } Index: drivers/Makefile =================================================================== RCS file: /cvsroot/linuxsh/linux/drivers/Makefile,v retrieving revision 1.4 diff -u -3 -p -r1.4 Makefile --- drivers/Makefile 1 Mar 2002 01:55:10 -0000 1.4 +++ drivers/Makefile 20 Mar 2002 01:46:38 -0000 @@ -10,7 +10,7 @@ mod-subdirs := dio mtd sbus video macint message/i2o message/fusion scsi md ieee1394 pnp isdn atm \ fc4 net/hamradio i2c acpi bluetooth input/serio input/gameport maple -subdir-y := base parport char block net sound misc media cdrom hotplug +subdir-y := base parport char block net misc media cdrom hotplug subdir-m := $(subdir-y) Index: drivers/net/8139too.c =================================================================== RCS file: /cvsroot/linuxsh/linux/drivers/net/8139too.c,v retrieving revision 1.7 diff -u -3 -p -r1.7 8139too.c --- drivers/net/8139too.c 1 Mar 2002 01:55:10 -0000 1.7 +++ drivers/net/8139too.c 20 Mar 2002 01:46:39 -0000 @@ -229,6 +229,7 @@ typedef enum { DFE538TX, DFE690TXD, FE2000VX, + ALLIED8139, SEGABBA, RTL8129, } board_t; @@ -248,6 +249,7 @@ static struct { { "D-Link DFE-538TX (RealTek RTL8139)", RTL8139_CAPS }, { "D-Link DFE-690TXD (RealTek RTL8139)", RTL8139_CAPS }, { "AboCom FE2000VX (RealTek RTL8139)", RTL8139_CAPS }, + { "Allied Telesyn 8139 CardBus", RTL8139_CAPS }, { "SEGA Broadband Adapter", RTL8139_CAPS }, { "RealTek RTL8129", RTL8129_CAPS }, }; @@ -263,6 +265,7 @@ static struct pci_device_id rtl8139_pci_ {0x1186, 0x1300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE538TX }, {0x1186, 0x1340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE690TXD }, {0x13d1, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FE2000VX }, + {0x1259, 0xa117, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALLIED8139 }, {0x11db, 0x1234, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SEGABBA }, #ifdef CONFIG_8139TOO_8129 @@ -1580,7 +1583,7 @@ static int rtl8139_thread (void *data) reparent_to_init(); spin_lock_irq(¤t->sigmask_lock); sigemptyset(¤t->blocked); - recalc_sigpending(current); + recalc_sigpending(); spin_unlock_irq(¤t->sigmask_lock); strncpy (current->comm, dev->name, sizeof(current->comm) - 1); @@ -1669,23 +1672,24 @@ static int rtl8139_start_xmit (struct sk struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; unsigned int entry; + unsigned int len = skb->len; /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; - if (likely(skb->len < TX_BUF_SIZE)) { + if (likely(len < TX_BUF_SIZE)) { skb_copy_and_csum_dev(skb, tp->tx_buf[entry]); dev_kfree_skb(skb); } else { dev_kfree_skb(skb); tp->stats.tx_dropped++; return 0; - } + } /* Note: the chip doesn't have auto-pad! */ spin_lock_irq(&tp->lock); RTL_W32_F (TxStatus0 + (entry * sizeof (u32)), - tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); + tp->tx_flag | max(len, (unsigned int)ETH_ZLEN)); dev->trans_start = jiffies; @@ -1696,8 +1700,8 @@ static int rtl8139_start_xmit (struct sk netif_stop_queue (dev); spin_unlock_irq(&tp->lock); - DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", - dev->name, skb->data, skb->len, entry); + DPRINTK ("%s: Queued Tx packet size %u to slot %d.\n", + dev->name, len, entry); return 0; } Index: drivers/net/Config.in =================================================================== RCS file: /cvsroot/linuxsh/linux/drivers/net/Config.in,v retrieving revision 1.4 diff -u -3 -p -r1.4 Config.in --- drivers/net/Config.in 1 Mar 2002 01:55:10 -0000 1.4 +++ drivers/net/Config.in 20 Mar 2002 01:46:39 -0000 @@ -37,7 +37,6 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; the bool ' Use AAUI port instead of TP by default' CONFIG_MACE_AAUI_PORT fi dep_tristate ' BMAC (G3 ethernet) support' CONFIG_BMAC $CONFIG_ALL_PPC - dep_tristate ' GMAC (G4/iBook ethernet) support' CONFIG_GMAC $CONFIG_ALL_PPC tristate ' National DP83902AV (Oak ethernet) support' CONFIG_OAKNET fi if [ "$CONFIG_ZORRO" = "y" ]; then Index: drivers/pci/pci.ids =================================================================== RCS file: /cvsroot/linuxsh/linux/drivers/pci/pci.ids,v retrieving revision 1.2 diff -u -3 -p -r1.2 pci.ids --- drivers/pci/pci.ids 3 Dec 2001 22:15:34 -0000 1.2 +++ drivers/pci/pci.ids 20 Mar 2002 01:46:39 -0000 @@ -1551,9 +1551,14 @@ 0001 i960 PCI bus interface 1076 VScom 800 8 port serial adaptor 1077 VScom 400 4 port serial adaptor + 9030 PCI <-> IOBus Bridge (Hot Swap) + 15ed 1002 Macrolink MCCS 8-port Serial (Hot Swap) + 15ed 1003 Macrolink MCCS 16-port Serial (Hot Swap) 9036 9036 9050 PCI <-> IOBus Bridge 10b5 2273 SH-ARC SoHard ARCnet card + 15ed 1000 Macrolink MCCS 8-port Serial + 15ed 1001 Macrolink MCCS 16-port Serial d84d 4006 EX-4006 1P d84d 4008 EX-4008 1P EPP/ECP d84d 4014 EX-4014 2P @@ -3943,6 +3948,12 @@ 1413 Addonics 1414 Microsoft Corporation 1415 Oxford Semiconductor Ltd + 9501 16PCI954 Function 0 + 15ed 2000 Macrolink MCCR Serial p0-3 of 8 + 15ed 2001 Macrolink MCCR Serial p0-3 of 16 + 9511 16PCI954 Function 1 + 15ed 2000 Macrolink MCCR Serial p4-7 of 8 + 15ed 2001 Macrolink MCCR Serial p4-15 of 16 1416 Multiwave Innovation pte Ltd 1417 Convergenet Technologies Inc 1418 Kyushu electronics systems Inc Index: include/asm-sh/pgtable.h =================================================================== RCS file: /cvsroot/linuxsh/linux/include/asm-sh/pgtable.h,v retrieving revision 1.4 diff -u -3 -p -r1.4 pgtable.h --- include/asm-sh/pgtable.h 24 Jan 2002 11:04:15 -0000 1.4 +++ include/asm-sh/pgtable.h 20 Mar 2002 01:46:39 -0000 @@ -41,6 +41,7 @@ extern void paging_init(void); #define flush_dcache_page(page) do { } while (0) #define flush_icache_range(start, end) do { } while (0) #define flush_icache_page(vma,pg) do { } while (0) +#define flush_icache_user_range(vma,pg,adr,len) do { } while (0) #define flush_cache_sigtramp(vaddr) do { } while (0) #define p3_cache_init() do { } while (0) @@ -64,6 +65,7 @@ extern void flush_cache_sigtramp(unsigne #define flush_page_to_ram(page) do { } while (0) #define flush_icache_page(vma,pg) do { } while (0) +#define flush_icache_user_range(vma,pg,adr,len) do { } while (0) /* Initialization of P3 area for copy_user_page */ extern void p3_cache_init(void); @@ -206,11 +208,6 @@ extern unsigned long empty_zero_page[102 #define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) #define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) -/* - * Permanent address of a page. Obviously must never be - * called on a highmem page. - */ -#define page_address(page) ((page)->virtual) /* P1 address of the page */ #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) #define pte_page(x) phys_to_page(pte_val(x)&PTE_PHYS_MASK) Index: include/net/inet_ecn.h =================================================================== RCS file: /cvsroot/linuxsh/linux/include/net/inet_ecn.h,v retrieving revision 1.2 diff -u -3 -p -r1.2 inet_ecn.h --- include/net/inet_ecn.h 20 Jan 2002 07:42:26 -0000 1.2 +++ include/net/inet_ecn.h 20 Mar 2002 01:46:39 -0000 @@ -28,15 +28,15 @@ static inline __u8 INET_ECN_encapsulate( return outer; } -#define INET_ECN_xmit(sk) do { (sk)->protinfo.af_inet.tos |= 2; } while (0) -#define INET_ECN_dontxmit(sk) do { (sk)->protinfo.af_inet.tos &= ~3; } while (0) +#define INET_ECN_xmit(sk) do { inet_sk(sk)->tos |= 2; } while (0) +#define INET_ECN_dontxmit(sk) do { inet_sk(sk)->tos &= ~3; } while (0) #define IP6_ECN_flow_init(label) do { \ (label) &= ~htonl(3<<20); \ } while (0) #define IP6_ECN_flow_xmit(sk, label) do { \ - if (INET_ECN_is_capable((sk)->protinfo.af_inet.tos)) \ + if (INET_ECN_is_capable(inet_sk(sk)->tos)) \ (label) |= __constant_htons(2 << 4); \ } while (0) Index: kernel/ptrace.c =================================================================== RCS file: /cvsroot/linuxsh/linux/kernel/ptrace.c,v retrieving revision 1.4 diff -u -3 -p -r1.4 ptrace.c --- kernel/ptrace.c 24 Jan 2002 10:28:23 -0000 1.4 +++ kernel/ptrace.c 20 Mar 2002 01:46:39 -0000 @@ -152,7 +152,7 @@ int access_process_vm(struct task_struct memcpy(maddr + offset, buf, bytes); flush_dcache_page(page); flush_page_to_ram(page); - flush_icache_page(vma, page); + flush_icache_user_range(vma, page, addr, bytes); } else { memcpy(buf, maddr + offset, bytes); flush_page_to_ram(page); Index: mm/memory.c =================================================================== RCS file: /cvsroot/linuxsh/linux/mm/memory.c,v retrieving revision 1.6 diff -u -3 -p -r1.6 memory.c --- mm/memory.c 24 Jan 2002 11:04:16 -0000 1.6 +++ mm/memory.c 20 Mar 2002 01:46:39 -0000 @@ -90,7 +90,7 @@ void __free_pte(pte_t pte) */ static inline void free_one_pmd(pmd_t * dir) { - pte_t * pte; + struct page *pte; if (pmd_none(*dir)) return; @@ -99,7 +99,7 @@ static inline void free_one_pmd(pmd_t * pmd_clear(dir); return; } - pte = pte_offset(dir, 0); + pte = pmd_page(*dir); pmd_clear(dir); pte_free(pte); } @@ -125,18 +125,6 @@ static inline void free_one_pgd(pgd_t * pmd_free(pmd); } -/* Low and high watermarks for page table cache. - The system should try to have pgt_water[0] <= cache elements <= pgt_water[1] - */ -int pgt_cache_water[2] = { 25, 50 }; - -/* Returns the number of pages freed */ -int check_pgt_cache(void) -{ - return do_check_pgt_cache(pgt_cache_water[0], pgt_cache_water[1]); -} - - /* * This function clears all user-level page tables of a process - this * is needed by execve(), so that old pages aren't in the way. @@ -152,11 +140,59 @@ void clear_page_tables(struct mm_struct page_dir++; } while (--nr); spin_unlock(&mm->page_table_lock); +} - /* keep the page table cache within bounds */ - check_pgt_cache(); +pte_t * pte_alloc_map(struct mm_struct *mm, pmd_t *pmd, unsigned long address) +{ + if (!pmd_present(*pmd)) { + struct page *new; + + spin_unlock(&mm->page_table_lock); + new = pte_alloc_one(mm, address); + spin_lock(&mm->page_table_lock); + if (!new) + return NULL; + + /* + * Because we dropped the lock, we should re-check the + * entry, as somebody else could have populated it.. + */ + if (pmd_present(*pmd)) { + pte_free(new); + goto out; + } + pmd_populate(mm, pmd, new); + } +out: + if (pmd_present(*pmd)) + return pte_offset_map(pmd, address); + return NULL; } +pte_t * pte_alloc_kernel(struct mm_struct *mm, pmd_t *pmd, unsigned long address) +{ + if (!pmd_present(*pmd)) { + pte_t *new; + + spin_unlock(&mm->page_table_lock); + new = pte_alloc_one_kernel(mm, address); + spin_lock(&mm->page_table_lock); + if (!new) + return NULL; + + /* + * Because we dropped the lock, we should re-check the + * entry, as somebody else could have populated it.. + */ + if (pmd_present(*pmd)) { + pte_free_kernel(new); + goto out; + } + pmd_populate_kernel(mm, pmd, new); + } +out: + return pte_offset_kernel(pmd, address); +} #define PTE_TABLE_MASK ((PTRS_PER_PTE-1) * sizeof(pte_t)) #define PMD_TABLE_MASK ((PTRS_PER_PMD-1) * sizeof(pmd_t)) @@ -169,7 +205,7 @@ void clear_page_tables(struct mm_struct * variable count and make things faster. -jj * * dst->page_table_lock is held on entry and exit, - * but may be dropped within pmd_alloc() and pte_alloc(). + * but may be dropped within pmd_alloc() and pte_alloc_map(). */ int copy_page_range(struct mm_struct *dst, struct mm_struct *src, struct vm_area_struct *vma) @@ -177,7 +213,7 @@ int copy_page_range(struct mm_struct *ds pgd_t * src_pgd, * dst_pgd; unsigned long address = vma->vm_start; unsigned long end = vma->vm_end; - unsigned long cow = (vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE; + unsigned long cow = (vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE; src_pgd = pgd_offset(src, address)-1; dst_pgd = pgd_offset(dst, address)-1; @@ -221,12 +257,11 @@ skip_copy_pte_range: address = (address goto cont_copy_pmd_range; } - src_pte = pte_offset(src_pmd, address); - dst_pte = pte_alloc(dst, dst_pmd, address); + dst_pte = pte_alloc_map(dst, dst_pmd, address); if (!dst_pte) goto nomem; - spin_lock(&src->page_table_lock); + src_pte = pte_offset_map_nested(src_pmd, address); do { pte_t pte = *src_pte; struct page *ptepage; @@ -245,7 +280,7 @@ skip_copy_pte_range: address = (address goto cont_copy_pte_range; /* If it's a COW mapping, write protect it both in the parent and the child */ - if (cow) { + if (cow && pte_write(pte)) { ptep_set_wrprotect(src_pte); pte = *src_pte; } @@ -259,11 +294,16 @@ skip_copy_pte_range: address = (address cont_copy_pte_range: set_pte(dst_pte, pte); cont_copy_pte_range_noset: address += PAGE_SIZE; - if (address >= end) + if (address >= end) { + pte_unmap_nested(src_pte); + pte_unmap(dst_pte); goto out_unlock; + } src_pte++; dst_pte++; } while ((unsigned long)src_pte & PTE_TABLE_MASK); + pte_unmap_nested(src_pte-1); + pte_unmap(dst_pte-1); spin_unlock(&src->page_table_lock); cont_copy_pmd_range: src_pmd++; @@ -292,7 +332,7 @@ static inline void forget_pte(pte_t page static inline int zap_pte_range(mmu_gather_t *tlb, pmd_t * pmd, unsigned long address, unsigned long size) { unsigned long offset; - pte_t * ptep; + pte_t *ptep; int freed = 0; if (pmd_none(*pmd)) @@ -302,7 +342,7 @@ static inline int zap_pte_range(mmu_gath pmd_clear(pmd); return 0; } - ptep = pte_offset(pmd, address); + ptep = pte_offset_map(pmd, address); offset = address & ~PMD_MASK; if (offset + size > PMD_SIZE) size = PMD_SIZE - offset; @@ -322,6 +362,7 @@ static inline int zap_pte_range(mmu_gath pte_clear(ptep); } } + pte_unmap(ptep-1); return freed; } @@ -415,11 +456,16 @@ static struct page * follow_page(struct if (pmd_none(*pmd) || pmd_bad(*pmd)) goto out; - ptep = pte_offset(pmd, address); - if (!ptep) + preempt_disable(); + ptep = pte_offset_map(pmd, address); + if (!ptep) { + preempt_enable(); goto out; + } pte = *ptep; + pte_unmap(ptep); + preempt_enable(); if (pte_present(pte)) { if (!write || (pte_write(pte) && pte_dirty(pte))) @@ -446,20 +492,25 @@ static inline struct page * get_page_map int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, int len, int write, int force, struct page **pages, struct vm_area_struct **vmas) { - int i = 0; + int i; + unsigned int flags; + + /* + * Require read or write permissions. + * If 'force' is set, we only require the "MAY" flags. + */ + flags = write ? (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD); + flags &= force ? (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE); + i = 0; + do { struct vm_area_struct * vma; vma = find_extend_vma(mm, start); - if ( !vma || - (!force && - ((write && (!(vma->vm_flags & VM_WRITE))) || - (!write && (!(vma->vm_flags & VM_READ))) ) )) { - if (i) return i; - return -EFAULT; - } + if ( !vma || !(flags & vma->vm_flags) ) + return i ? : -EFAULT; spin_lock(&mm->page_table_lock); do { @@ -748,10 +799,11 @@ static inline int zeromap_pmd_range(stru if (end > PGDIR_SIZE) end = PGDIR_SIZE; do { - pte_t * pte = pte_alloc(mm, pmd, address); + pte_t * pte = pte_alloc_map(mm, pmd, address); if (!pte) return -ENOMEM; zeromap_pte_range(pte, address, end - address, prot); + pte_unmap(pte); address = (address + PMD_SIZE) & PMD_MASK; pmd++; } while (address && (address < end)); @@ -828,10 +880,11 @@ static inline int remap_pmd_range(struct end = PGDIR_SIZE; phys_addr -= address; do { - pte_t * pte = pte_alloc(mm, pmd, address); + pte_t * pte = pte_alloc_map(mm, pmd, address); if (!pte) return -ENOMEM; remap_pte_range(pte, address, end - address, address + phys_addr, prot); + pte_unmap(pte); address = (address + PMD_SIZE) & PMD_MASK; pmd++; } while (address && (address < end)); @@ -919,7 +972,7 @@ static inline void break_cow(struct vm_a * with the page_table_lock released. */ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, - unsigned long address, pte_t *page_table, pte_t pte) + unsigned long address, pte_t *page_table, pmd_t *pmd, pte_t pte) { struct page *old_page, *new_page; @@ -935,10 +988,12 @@ static int do_wp_page(struct mm_struct * flush_cache_page(vma, address); #endif establish_pte(vma, address, page_table, pte_mkyoung(pte_mkdirty(pte_mkwrite(pte)))); + pte_unmap(page_table); spin_unlock(&mm->page_table_lock); return 1; /* Minor fault */ } } + pte_unmap(page_table); /* * Ok, we need to copy. Oh, well.. @@ -955,6 +1010,7 @@ static int do_wp_page(struct mm_struct * * Re-check the pte - we dropped the lock */ spin_lock(&mm->page_table_lock); + page_table = pte_offset_map(pmd, address); if (pte_same(*page_table, pte)) { if (PageReserved(old_page)) ++mm->rss; @@ -964,12 +1020,14 @@ static int do_wp_page(struct mm_struct * /* Free the old page.. */ new_page = old_page; } + pte_unmap(page_table); spin_unlock(&mm->page_table_lock); page_cache_release(new_page); page_cache_release(old_page); return 1; /* Minor fault */ bad_wp_page: + pte_unmap(page_table); spin_unlock(&mm->page_table_lock); printk("do_wp_page: bogus page at address %08lx (page 0x%lx)\n",address,(unsigned long)old_page); return -1; @@ -1052,11 +1110,8 @@ do_expand: inode->i_size = offset; out_truncate: - if (inode->i_op && inode->i_op->truncate) { - lock_kernel(); + if (inode->i_op && inode->i_op->truncate) inode->i_op->truncate(inode); - unlock_kernel(); - } out: return 0; } @@ -1093,13 +1148,14 @@ void swapin_readahead(swp_entry_t entry) */ static int do_swap_page(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long address, - pte_t * page_table, pte_t orig_pte, int write_access) + pte_t *page_table, pmd_t *pmd, pte_t orig_pte, int write_access) { struct page *page; swp_entry_t entry = pte_to_swp_entry(orig_pte); pte_t pte; int ret = 1; + pte_unmap(page_table); spin_unlock(&mm->page_table_lock); page = lookup_swap_cache(entry); if (!page) { @@ -1112,7 +1168,9 @@ static int do_swap_page(struct mm_struct */ int retval; spin_lock(&mm->page_table_lock); + page_table = pte_offset_map(pmd, address); retval = pte_same(*page_table, orig_pte) ? -1 : 1; + pte_unmap(page_table); spin_unlock(&mm->page_table_lock); return retval; } @@ -1128,7 +1186,9 @@ static int do_swap_page(struct mm_struct * released the page table lock. */ spin_lock(&mm->page_table_lock); + page_table = pte_offset_map(pmd, address); if (!pte_same(*page_table, orig_pte)) { + pte_unmap(page_table); spin_unlock(&mm->page_table_lock); unlock_page(page); page_cache_release(page); @@ -1153,6 +1213,7 @@ static int do_swap_page(struct mm_struct /* No need to invalidate - it was non-present before */ update_mmu_cache(vma, address, pte); + pte_unmap(page_table); spin_unlock(&mm->page_table_lock); return ret; } @@ -1162,7 +1223,7 @@ static int do_swap_page(struct mm_struct * spinlock held to protect against concurrent faults in * multithreaded programs. */ -static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, pte_t *page_table, int write_access, unsigned long addr) +static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, pte_t *page_table, pmd_t *pmd, int write_access, unsigned long addr) { pte_t entry; @@ -1174,6 +1235,7 @@ static int do_anonymous_page(struct mm_s struct page *page; /* Allocate our own private page. */ + pte_unmap(page_table); spin_unlock(&mm->page_table_lock); page = alloc_page(GFP_HIGHUSER); @@ -1182,7 +1244,10 @@ static int do_anonymous_page(struct mm_s clear_user_highpage(page, addr); spin_lock(&mm->page_table_lock); + page_table = pte_offset_map(pmd, addr); + if (!pte_none(*page_table)) { + pte_unmap(page_table); page_cache_release(page); spin_unlock(&mm->page_table_lock); return 1; @@ -1194,6 +1259,7 @@ static int do_anonymous_page(struct mm_s } set_pte(page_table, entry); + pte_unmap(page_table); /* No need to invalidate - it was non-present before */ update_mmu_cache(vma, addr, entry); @@ -1217,13 +1283,14 @@ no_mem: * spinlock held. Exit with the spinlock released. */ static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma, - unsigned long address, int write_access, pte_t *page_table) + unsigned long address, int write_access, pte_t *page_table, pmd_t *pmd) { struct page * new_page; pte_t entry; if (!vma->vm_ops || !vma->vm_ops->nopage) - return do_anonymous_page(mm, vma, page_table, write_access, address); + return do_anonymous_page(mm, vma, page_table, pmd, write_access, address); + pte_unmap(page_table); spin_unlock(&mm->page_table_lock); new_page = vma->vm_ops->nopage(vma, address & PAGE_MASK, 0); @@ -1249,6 +1316,8 @@ static int do_no_page(struct mm_struct * } spin_lock(&mm->page_table_lock); + page_table = pte_offset_map(pmd, address); + /* * This silly early PAGE_DIRTY setting removes a race * due to the bad i386 page protection. But it's valid @@ -1268,8 +1337,10 @@ static int do_no_page(struct mm_struct * if (write_access) entry = pte_mkwrite(pte_mkdirty(entry)); set_pte(page_table, entry); + pte_unmap(page_table); } else { /* One of our sibling threads was faster, back out. */ + pte_unmap(page_table); page_cache_release(new_page); spin_unlock(&mm->page_table_lock); return 1; @@ -1304,7 +1375,7 @@ static int do_no_page(struct mm_struct * */ static inline int handle_pte_fault(struct mm_struct *mm, struct vm_area_struct * vma, unsigned long address, - int write_access, pte_t * pte) + int write_access, pte_t *pte, pmd_t *pmd) { pte_t entry; @@ -1316,18 +1387,19 @@ static inline int handle_pte_fault(struc * drop the lock. */ if (pte_none(entry)) - return do_no_page(mm, vma, address, write_access, pte); - return do_swap_page(mm, vma, address, pte, entry, write_access); + return do_no_page(mm, vma, address, write_access, pte, pmd); + return do_swap_page(mm, vma, address, pte, pmd, entry, write_access); } if (write_access) { if (!pte_write(entry)) - return do_wp_page(mm, vma, address, pte, entry); + return do_wp_page(mm, vma, address, pte, pmd, entry); entry = pte_mkdirty(entry); } entry = pte_mkyoung(entry); establish_pte(vma, address, pte, entry); + pte_unmap(pte); spin_unlock(&mm->page_table_lock); return 1; } @@ -1352,9 +1424,9 @@ int handle_mm_fault(struct mm_struct *mm pmd = pmd_alloc(mm, pgd, address); if (pmd) { - pte_t * pte = pte_alloc(mm, pmd, address); + pte_t * pte = pte_alloc_map(mm, pmd, address); if (pte) - return handle_pte_fault(mm, vma, address, write_access, pte); + return handle_pte_fault(mm, vma, address, write_access, pte, pmd); } spin_unlock(&mm->page_table_lock); return -1; @@ -1373,64 +1445,25 @@ pmd_t *__pmd_alloc(struct mm_struct *mm, { pmd_t *new; - /* "fast" allocation can happen without dropping the lock.. */ - new = pmd_alloc_one_fast(mm, address); - if (!new) { - spin_unlock(&mm->page_table_lock); - new = pmd_alloc_one(mm, address); - spin_lock(&mm->page_table_lock); - if (!new) - return NULL; + spin_unlock(&mm->page_table_lock); + new = pmd_alloc_one(mm, address); + spin_lock(&mm->page_table_lock); + if (!new) + return NULL; - /* - * Because we dropped the lock, we should re-check the - * entry, as somebody else could have populated it.. - */ - if (!pgd_none(*pgd)) { - pmd_free(new); - goto out; - } + /* + * Because we dropped the lock, we should re-check the + * entry, as somebody else could have populated it.. + */ + if (pgd_present(*pgd)) { + pmd_free(new); + goto out; } pgd_populate(mm, pgd, new); out: return pmd_offset(pgd, address); } -/* - * Allocate the page table directory. - * - * We've already handled the fast-path in-line, and we own the - * page table lock. - */ -pte_t *pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address) -{ - if (pmd_none(*pmd)) { - pte_t *new; - - /* "fast" allocation can happen without dropping the lock.. */ - new = pte_alloc_one_fast(mm, address); - if (!new) { - spin_unlock(&mm->page_table_lock); - new = pte_alloc_one(mm, address); - spin_lock(&mm->page_table_lock); - if (!new) - return NULL; - - /* - * Because we dropped the lock, we should re-check the - * entry, as somebody else could have populated it.. - */ - if (!pmd_none(*pmd)) { - pte_free(new); - goto out; - } - } - pmd_populate(mm, pmd, new); - } -out: - return pte_offset(pmd, address); -} - int make_pages_present(unsigned long addr, unsigned long end) { int ret, len, write; @@ -1446,4 +1479,29 @@ int make_pages_present(unsigned long add ret = get_user_pages(current, current->mm, addr, len, write, 0, NULL, NULL); return ret == len ? 0 : -1; +} + +/* + * Map a vmalloc()-space virtual address to the physical page. + */ +struct page * vmalloc_to_page(unsigned long addr) +{ + struct page *page = NULL; + pgd_t *pgd = pgd_offset_k(addr); + pmd_t *pmd; + pte_t *ptep, pte; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, addr); + if (!pmd_none(*pmd)) { + preempt_disable(); + ptep = pte_offset_map(pmd, addr); + pte = *ptep; + if (pte_present(pte)) + page = pte_page(pte); + pte_unmap(ptep); + preempt_enable(); + } + } + return page; } |