diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/i386/kernel/alternative.c | 6 | ||||
-rw-r--r-- | arch/i386/mm/init.c | 9 | ||||
-rw-r--r-- | arch/parisc/mm/init.c | 4 | ||||
-rw-r--r-- | arch/s390/kernel/entry.S | 9 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 1 | ||||
-rw-r--r-- | arch/s390/mm/init.c | 35 | ||||
-rw-r--r-- | arch/um/kernel/skas/uaccess.c | 15 | ||||
-rw-r--r-- | arch/um/os-Linux/umid.c | 97 | ||||
-rw-r--r-- | arch/um/scripts/Makefile.rules | 4 | ||||
-rw-r--r-- | arch/x86_64/mm/init.c | 7 |
10 files changed, 118 insertions, 69 deletions
diff --git a/arch/i386/kernel/alternative.c b/arch/i386/kernel/alternative.c index 50eb0e03777..7b421b3a053 100644 --- a/arch/i386/kernel/alternative.c +++ b/arch/i386/kernel/alternative.c @@ -168,6 +168,8 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end) } } +#ifdef CONFIG_SMP + static void alternatives_smp_save(struct alt_instr *start, struct alt_instr *end) { struct alt_instr *a; @@ -328,6 +330,8 @@ void alternatives_smp_switch(int smp) spin_unlock_irqrestore(&smp_alt, flags); } +#endif + void __init alternative_instructions(void) { if (no_replacement) { @@ -349,6 +353,7 @@ void __init alternative_instructions(void) smp_alt_once = 1; #endif +#ifdef CONFIG_SMP if (smp_alt_once) { if (1 == num_possible_cpus()) { printk(KERN_INFO "SMP alternatives: switching to UP code\n"); @@ -370,4 +375,5 @@ void __init alternative_instructions(void) _text, _etext); alternatives_smp_switch(0); } +#endif } diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index dc5d8979cd6..89e8486aac3 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -725,16 +725,15 @@ static int noinline do_test_wp_bit(void) #ifdef CONFIG_DEBUG_RODATA -extern char __start_rodata, __end_rodata; void mark_rodata_ro(void) { - unsigned long addr = (unsigned long)&__start_rodata; + unsigned long addr = (unsigned long)__start_rodata; - for (; addr < (unsigned long)&__end_rodata; addr += PAGE_SIZE) + for (; addr < (unsigned long)__end_rodata; addr += PAGE_SIZE) change_page_attr(virt_to_page(addr), 1, PAGE_KERNEL_RO); - printk ("Write protecting the kernel read-only data: %luk\n", - (unsigned long)(&__end_rodata - &__start_rodata) >> 10); + printk("Write protecting the kernel read-only data: %uk\n", + (__end_rodata - __start_rodata) >> 10); /* * change_page_attr() requires a global_flush_tlb() call after it. diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index b64602a99d8..f2b96f1e0da 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -27,6 +27,7 @@ #include <asm/tlb.h> #include <asm/pdc_chassis.h> #include <asm/mmzone.h> +#include <asm/sections.h> DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); @@ -417,11 +418,10 @@ void free_initmem(void) #ifdef CONFIG_DEBUG_RODATA void mark_rodata_ro(void) { - extern char __start_rodata, __end_rodata; /* rodata memory was already mapped with KERNEL_RO access rights by pagetable_init() and map_pages(). No need to do additional stuff here */ printk (KERN_INFO "Write protecting the kernel read-only data: %luk\n", - (unsigned long)(&__end_rodata - &__start_rodata) >> 10); + (unsigned long)(__end_rodata - __start_rodata) >> 10); } #endif diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 1a434a7004e..d8948c342ca 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -228,8 +228,9 @@ sysc_do_svc: sysc_nr_ok: mvc SP_ARGS(4,%r15),SP_R7(%r15) sysc_do_restart: + l %r8,BASED(.Lsysc_table) tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) - l %r8,sys_call_table-system_call(%r7,%r13) # get system call addr. + l %r8,0(%r7,%r8) # get system call addr. bnz BASED(sysc_tracesys) basr %r14,%r8 # call sys_xxxx st %r2,SP_R2(%r15) # store return value (change R2 on stack) @@ -330,9 +331,10 @@ sysc_tracesys: basr %r14,%r1 clc SP_R2(4,%r15),BASED(.Lnr_syscalls) bnl BASED(sysc_tracenogo) + l %r8,BASED(.Lsysc_table) l %r7,SP_R2(%r15) # strace might have changed the sll %r7,2 # system call - l %r8,sys_call_table-system_call(%r7,%r13) + l %r8,0(%r7,%r8) sysc_tracego: lm %r3,%r6,SP_R3(%r15) l %r2,SP_ORIG_R2(%r15) @@ -1009,6 +1011,7 @@ cleanup_io_leave_insn: .Ltrace: .long syscall_trace .Lvfork: .long sys_vfork .Lschedtail: .long schedule_tail +.Lsysc_table: .long sys_call_table .Lcritical_start: .long __critical_start + 0x80000000 @@ -1017,8 +1020,8 @@ cleanup_io_leave_insn: .Lcleanup_critical: .long cleanup_critical + .section .rodata, "a" #define SYSCALL(esa,esame,emu) .long esa sys_call_table: #include "syscalls.S" #undef SYSCALL - diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index edad6077167..1ca499fa54b 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -991,6 +991,7 @@ cleanup_io_leave_insn: .Lcritical_end: .quad __critical_end + .section .rodata, "a" #define SYSCALL(esa,esame,emu) .long esame sys_call_table: #include "syscalls.S" diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 81dce185f83..eb6ebfef134 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -23,6 +23,7 @@ #include <linux/init.h> #include <linux/pagemap.h> #include <linux/bootmem.h> +#include <linux/pfn.h> #include <asm/processor.h> #include <asm/system.h> @@ -33,6 +34,7 @@ #include <asm/lowcore.h> #include <asm/tlb.h> #include <asm/tlbflush.h> +#include <asm/sections.h> DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); @@ -89,17 +91,6 @@ void show_mem(void) printk("%d pages swap cached\n",cached); } -/* References to section boundaries */ - -extern unsigned long _text; -extern unsigned long _etext; -extern unsigned long _edata; -extern unsigned long __bss_start; -extern unsigned long _end; - -extern unsigned long __init_begin; -extern unsigned long __init_end; - extern unsigned long __initdata zholes_size[]; /* * paging_init() sets up the page tables @@ -116,6 +107,10 @@ void __init paging_init(void) unsigned long pfn = 0; unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE; static const int ssm_mask = 0x04000000L; + unsigned long ro_start_pfn, ro_end_pfn; + + ro_start_pfn = PFN_DOWN((unsigned long)&__start_rodata); + ro_end_pfn = PFN_UP((unsigned long)&__end_rodata); /* unmap whole virtual address space */ @@ -143,7 +138,10 @@ void __init paging_init(void) pg_dir++; for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) { - pte = pfn_pte(pfn, PAGE_KERNEL); + if (pfn >= ro_start_pfn && pfn < ro_end_pfn) + pte = pfn_pte(pfn, __pgprot(_PAGE_RO)); + else + pte = pfn_pte(pfn, PAGE_KERNEL); if (pfn >= max_low_pfn) pte_clear(&init_mm, 0, &pte); set_pte(pg_table, pte); @@ -175,6 +173,7 @@ void __init paging_init(void) } #else /* CONFIG_64BIT */ + void __init paging_init(void) { pgd_t * pg_dir; @@ -186,13 +185,15 @@ void __init paging_init(void) unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERN_REGION_TABLE; static const int ssm_mask = 0x04000000L; - unsigned long zones_size[MAX_NR_ZONES]; unsigned long dma_pfn, high_pfn; + unsigned long ro_start_pfn, ro_end_pfn; memset(zones_size, 0, sizeof(zones_size)); dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT; high_pfn = max_low_pfn; + ro_start_pfn = PFN_DOWN((unsigned long)&__start_rodata); + ro_end_pfn = PFN_UP((unsigned long)&__end_rodata); if (dma_pfn > high_pfn) zones_size[ZONE_DMA] = high_pfn; @@ -231,7 +232,10 @@ void __init paging_init(void) pmd_populate_kernel(&init_mm, pm_dir, pt_dir); for (k = 0 ; k < PTRS_PER_PTE ; k++,pt_dir++) { - pte = pfn_pte(pfn, PAGE_KERNEL); + if (pfn >= ro_start_pfn && pfn < ro_end_pfn) + pte = pfn_pte(pfn, __pgprot(_PAGE_RO)); + else + pte = pfn_pte(pfn, PAGE_KERNEL); if (pfn >= max_low_pfn) { pte_clear(&init_mm, 0, &pte); continue; @@ -282,6 +286,9 @@ void __init mem_init(void) reservedpages << (PAGE_SHIFT-10), datasize >>10, initsize >> 10); + printk("Write protected kernel read-only data: %#lx - %#lx\n", + (unsigned long)&__start_rodata, + PFN_ALIGN((unsigned long)&__end_rodata) - 1); } void free_initmem(void) diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index 5992c325716..8912cec0fe4 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -8,6 +8,7 @@ #include "linux/kernel.h" #include "linux/string.h" #include "linux/fs.h" +#include "linux/hardirq.h" #include "linux/highmem.h" #include "asm/page.h" #include "asm/pgtable.h" @@ -38,7 +39,7 @@ static unsigned long maybe_map(unsigned long virt, int is_write) return((unsigned long) phys); } -static int do_op(unsigned long addr, int len, int is_write, +static int do_op_one_page(unsigned long addr, int len, int is_write, int (*op)(unsigned long addr, int len, void *arg), void *arg) { struct page *page; @@ -49,9 +50,11 @@ static int do_op(unsigned long addr, int len, int is_write, return(-1); page = phys_to_page(addr); - addr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK); + addr = (unsigned long) kmap_atomic(page, KM_UML_USERCOPY) + (addr & ~PAGE_MASK); + n = (*op)(addr, len, arg); - kunmap(page); + + kunmap_atomic(page, KM_UML_USERCOPY); return(n); } @@ -77,7 +80,7 @@ static void do_buffer_op(void *jmpbuf, void *arg_ptr) remain = len; current->thread.fault_catcher = jmpbuf; - n = do_op(addr, size, is_write, op, arg); + n = do_op_one_page(addr, size, is_write, op, arg); if(n != 0){ *res = (n < 0 ? remain : 0); goto out; @@ -91,7 +94,7 @@ static void do_buffer_op(void *jmpbuf, void *arg_ptr) } while(addr < ((addr + remain) & PAGE_MASK)){ - n = do_op(addr, PAGE_SIZE, is_write, op, arg); + n = do_op_one_page(addr, PAGE_SIZE, is_write, op, arg); if(n != 0){ *res = (n < 0 ? remain : 0); goto out; @@ -105,7 +108,7 @@ static void do_buffer_op(void *jmpbuf, void *arg_ptr) goto out; } - n = do_op(addr, remain, is_write, op, arg); + n = do_op_one_page(addr, remain, is_write, op, arg); if(n != 0) *res = (n < 0 ? remain : 0); else *res = 0; diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c index 362db059fe3..48092b95c8a 100644 --- a/arch/um/os-Linux/umid.c +++ b/arch/um/os-Linux/umid.c @@ -67,32 +67,53 @@ err: return err; } -static int actually_do_remove(char *dir) +/* + * Unlinks the files contained in @dir and then removes @dir. + * Doesn't handle directory trees, so it's not like rm -rf, but almost such. We + * ignore ENOENT errors for anything (they happen, strangely enough - possibly due + * to races between multiple dying UML threads). + */ +static int remove_files_and_dir(char *dir) { DIR *directory; struct dirent *ent; int len; char file[256]; + int ret; directory = opendir(dir); - if(directory == NULL) - return -errno; + if (directory == NULL) { + if (errno != ENOENT) + return -errno; + else + return 0; + } - while((ent = readdir(directory)) != NULL){ - if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) + while ((ent = readdir(directory)) != NULL) { + if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue; len = strlen(dir) + sizeof("/") + strlen(ent->d_name) + 1; - if(len > sizeof(file)) - return -E2BIG; + if (len > sizeof(file)) { + ret = -E2BIG; + goto out; + } sprintf(file, "%s/%s", dir, ent->d_name); - if(unlink(file) < 0) - return -errno; + if (unlink(file) < 0 && errno != ENOENT) { + ret = -errno; + goto out; + } } - if(rmdir(dir) < 0) - return -errno; - return 0; + if (rmdir(dir) < 0 && errno != ENOENT) { + ret = -errno; + goto out; + } + + ret = 0; +out: + closedir(directory); + return ret; } /* This says that there isn't already a user of the specified directory even if @@ -103,9 +124,10 @@ static int actually_do_remove(char *dir) * something other than UML sticking stuff in the directory * this boot racing with a shutdown of the other UML * In any of these cases, the directory isn't useful for anything else. + * + * Boolean return: 1 if in use, 0 otherwise. */ - -static int not_dead_yet(char *dir) +static inline int is_umdir_used(char *dir) { char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; char pid[sizeof("nnnnn\0")], *end; @@ -113,7 +135,7 @@ static int not_dead_yet(char *dir) n = snprintf(file, sizeof(file), "%s/pid", dir); if(n >= sizeof(file)){ - printk("not_dead_yet - pid filename too long\n"); + printk("is_umdir_used - pid filename too long\n"); err = -E2BIG; goto out; } @@ -123,7 +145,7 @@ static int not_dead_yet(char *dir) if(fd < 0) { fd = -errno; if(fd != -ENOENT){ - printk("not_dead_yet : couldn't open pid file '%s', " + printk("is_umdir_used : couldn't open pid file '%s', " "err = %d\n", file, -fd); } goto out; @@ -132,18 +154,18 @@ static int not_dead_yet(char *dir) err = 0; n = read(fd, pid, sizeof(pid)); if(n < 0){ - printk("not_dead_yet : couldn't read pid file '%s', " + printk("is_umdir_used : couldn't read pid file '%s', " "err = %d\n", file, errno); goto out_close; } else if(n == 0){ - printk("not_dead_yet : couldn't read pid file '%s', " + printk("is_umdir_used : couldn't read pid file '%s', " "0-byte read\n", file); goto out_close; } p = strtoul(pid, &end, 0); if(end == pid){ - printk("not_dead_yet : couldn't parse pid file '%s', " + printk("is_umdir_used : couldn't parse pid file '%s', " "errno = %d\n", file, errno); goto out_close; } @@ -153,19 +175,32 @@ static int not_dead_yet(char *dir) return 1; } - err = actually_do_remove(dir); - if(err) - printk("not_dead_yet - actually_do_remove failed with " - "err = %d\n", err); - - return err; - out_close: close(fd); out: return 0; } +/* + * Try to remove the directory @dir unless it's in use. + * Precondition: @dir exists. + * Returns 0 for success, < 0 for failure in removal or if the directory is in + * use. + */ +static int umdir_take_if_dead(char *dir) +{ + int ret; + if (is_umdir_used(dir)) + return -EEXIST; + + ret = remove_files_and_dir(dir); + if (ret) { + printk("is_umdir_used - remove_files_and_dir failed with " + "err = %d\n", ret); + } + return ret; +} + static void __init create_pid_file(void) { char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; @@ -244,11 +279,7 @@ int __init make_umid(void) if(err != -EEXIST) goto err; - /* 1 -> this umid is already in use - * < 0 -> we couldn't remove the umid directory - * In either case, we can't use this umid, so return -EEXIST. - */ - if(not_dead_yet(tmp) != 0) + if (umdir_take_if_dead(tmp) < 0) goto err; err = mkdir(tmp, 0777); @@ -344,9 +375,9 @@ static void remove_umid_dir(void) char dir[strlen(uml_dir) + UMID_LEN + 1], err; sprintf(dir, "%s%s", uml_dir, umid); - err = actually_do_remove(dir); + err = remove_files_and_dir(dir); if(err) - printf("remove_umid_dir - actually_do_remove failed with " + printf("remove_umid_dir - remove_files_and_dir failed with " "err = %d\n", err); } diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules index 1347dc6d521..813077fb1e5 100644 --- a/arch/um/scripts/Makefile.rules +++ b/arch/um/scripts/Makefile.rules @@ -8,7 +8,7 @@ USER_OBJS += $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) $(USER_OBJS:.o=.%): \ - c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) $(CFLAGS_$(*F).o) + c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) $(CFLAGS_$(basetarget).o) $(USER_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \ -Dunix -D__unix__ -D__$(SUBARCH)__ @@ -17,7 +17,7 @@ $(USER_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \ UNPROFILE_OBJS := $(foreach file,$(UNPROFILE_OBJS),$(obj)/$(file)) $(UNPROFILE_OBJS:.o=.%): \ - c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS)) $(CFLAGS_$(*F).o) + c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS)) $(CFLAGS_$(basetarget).o) $(UNPROFILE_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \ -Dunix -D__unix__ -D__$(SUBARCH)__ diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index 72f140f81b7..d14fb2dfbfc 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -678,16 +678,15 @@ void free_initmem(void) #ifdef CONFIG_DEBUG_RODATA -extern char __start_rodata, __end_rodata; void mark_rodata_ro(void) { - unsigned long addr = (unsigned long)&__start_rodata; + unsigned long addr = (unsigned long)__start_rodata; - for (; addr < (unsigned long)&__end_rodata; addr += PAGE_SIZE) + for (; addr < (unsigned long)__end_rodata; addr += PAGE_SIZE) change_page_attr_addr(addr, 1, PAGE_KERNEL_RO); printk ("Write protecting the kernel read-only data: %luk\n", - (&__end_rodata - &__start_rodata) >> 10); + (__end_rodata - __start_rodata) >> 10); /* * change_page_attr_addr() requires a global_flush_tlb() call after it. |