diff options
50 files changed, 931 insertions, 369 deletions
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index e8c965ce86e..e34f651fa13 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -683,24 +683,18 @@ void do_syscall_trace(struct pt_regs *regs, int entryexit) /* do the secure computing check first */ secure_computing(regs->orig_eax); - if (unlikely(current->audit_context)) { - if (!entryexit) - audit_syscall_entry(current, regs->orig_eax, - regs->ebx, regs->ecx, - regs->edx, regs->esi); - else - audit_syscall_exit(current, regs->eax); - } + if (unlikely(current->audit_context) && entryexit) + audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax); if (!(current->ptrace & PT_PTRACED)) - return; + goto out; /* Fake a debug trap */ if (test_thread_flag(TIF_SINGLESTEP)) send_sigtrap(current, regs, 0); if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; + goto out; /* the 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ @@ -715,4 +709,9 @@ void do_syscall_trace(struct pt_regs *regs, int entryexit) send_sig(current->exit_code, current, 1); current->exit_code = 0; } + out: + if (unlikely(current->audit_context) && !entryexit) + audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax, + regs->ebx, regs->ecx, regs->edx, regs->esi); + } diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index c253fd5914f..907464ee727 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1596,20 +1596,25 @@ syscall_trace_enter (long arg0, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, struct pt_regs regs) { - long syscall; + if (test_thread_flag(TIF_SYSCALL_TRACE) + && (current->ptrace & PT_PTRACED)) + syscall_trace(); if (unlikely(current->audit_context)) { - if (IS_IA32_PROCESS(®s)) + long syscall; + int arch; + + if (IS_IA32_PROCESS(®s)) { syscall = regs.r1; - else + arch = AUDIT_ARCH_I386; + } else { syscall = regs.r15; + arch = AUDIT_ARCH_IA64; + } - audit_syscall_entry(current, syscall, arg0, arg1, arg2, arg3); + audit_syscall_entry(current, arch, syscall, arg0, arg1, arg2, arg3); } - if (test_thread_flag(TIF_SYSCALL_TRACE) - && (current->ptrace & PT_PTRACED)) - syscall_trace(); } /* "asmlinkage" so the input arguments are preserved... */ @@ -1620,7 +1625,7 @@ syscall_trace_leave (long arg0, long arg1, long arg2, long arg3, struct pt_regs regs) { if (unlikely(current->audit_context)) - audit_syscall_exit(current, regs.r8); + audit_syscall_exit(current, AUDITSC_RESULT(regs.r10), regs.r8); if (test_thread_flag(TIF_SYSCALL_TRACE) && (current->ptrace & PT_PTRACED)) diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index a2f899c2f4d..92e70ca3bff 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -301,25 +301,38 @@ out: return ret; } +static inline int audit_arch(void) +{ +#ifdef CONFIG_CPU_LITTLE_ENDIAN +#ifdef CONFIG_MIPS64 + if (!(current->thread.mflags & MF_32BIT_REGS)) + return AUDIT_ARCH_MIPSEL64; +#endif /* MIPS64 */ + return AUDIT_ARCH_MIPSEL; + +#else /* big endian... */ +#ifdef CONFIG_MIPS64 + if (!(current->thread.mflags & MF_32BIT_REGS)) + return AUDIT_ARCH_MIPS64; +#endif /* MIPS64 */ + return AUDIT_ARCH_MIPS; + +#endif /* endian */ +} + /* * Notification of system call entry/exit * - triggered by current->work.syscall_trace */ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) { - if (unlikely(current->audit_context)) { - if (!entryexit) - audit_syscall_entry(current, regs->regs[2], - regs->regs[4], regs->regs[5], - regs->regs[6], regs->regs[7]); - else - audit_syscall_exit(current, regs->regs[2]); - } + if (unlikely(current->audit_context) && entryexit) + audit_syscall_exit(current, AUDITSC_RESULT(regs->regs[2]), regs->regs[2]); if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; + goto out; if (!(current->ptrace & PT_PTRACED)) - return; + goto out; /* The 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ @@ -335,4 +348,9 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) send_sig(current->exit_code, current, 1); current->exit_code = 0; } + out: + if (unlikely(current->audit_context) && !entryexit) + audit_syscall_entry(current, audit_arch(), regs->regs[2], + regs->regs[4], regs->regs[5], + regs->regs[6], regs->regs[7]); } diff --git a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c index 5a846324ca8..9f8c6087ae5 100644 --- a/arch/ppc64/kernel/ptrace.c +++ b/arch/ppc64/kernel/ptrace.c @@ -305,14 +305,17 @@ static void do_syscall_trace(void) void do_syscall_trace_enter(struct pt_regs *regs) { + if (test_thread_flag(TIF_SYSCALL_TRACE) + && (current->ptrace & PT_PTRACED)) + do_syscall_trace(); + if (unlikely(current->audit_context)) - audit_syscall_entry(current, regs->gpr[0], + audit_syscall_entry(current, + test_thread_flag(TIF_32BIT)?AUDIT_ARCH_PPC:AUDIT_ARCH_PPC64, + regs->gpr[0], regs->gpr[3], regs->gpr[4], regs->gpr[5], regs->gpr[6]); - if (test_thread_flag(TIF_SYSCALL_TRACE) - && (current->ptrace & PT_PTRACED)) - do_syscall_trace(); } void do_syscall_trace_leave(struct pt_regs *regs) @@ -320,7 +323,9 @@ void do_syscall_trace_leave(struct pt_regs *regs) secure_computing(regs->gpr[0]); if (unlikely(current->audit_context)) - audit_syscall_exit(current, regs->result); + audit_syscall_exit(current, + (regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, + regs->result); if ((test_thread_flag(TIF_SYSCALL_TRACE) || test_thread_flag(TIF_SINGLESTEP)) diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 9f0d73e3f5f..26889366929 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -712,18 +712,13 @@ out: asmlinkage void syscall_trace(struct pt_regs *regs, int entryexit) { - if (unlikely(current->audit_context)) { - if (!entryexit) - audit_syscall_entry(current, regs->gprs[2], - regs->orig_gpr2, regs->gprs[3], - regs->gprs[4], regs->gprs[5]); - else - audit_syscall_exit(current, regs->gprs[2]); - } + if (unlikely(current->audit_context) && entryexit) + audit_syscall_exit(current, AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]); + if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; + goto out; if (!(current->ptrace & PT_PTRACED)) - return; + goto out; ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); @@ -736,4 +731,10 @@ syscall_trace(struct pt_regs *regs, int entryexit) send_sig(current->exit_code, current, 1); current->exit_code = 0; } + out: + if (unlikely(current->audit_context) && !entryexit) + audit_syscall_entry(current, + test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X, + regs->gprs[2], regs->orig_gpr2, regs->gprs[3], + regs->gprs[4], regs->gprs[5]); } diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index e50e60ff5d2..959b2d2490d 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -337,15 +337,18 @@ void syscall_trace(union uml_pt_regs *regs, int entryexit) if (unlikely(current->audit_context)) { if (!entryexit) - audit_syscall_entry(current, - UPT_SYSCALL_NR(®s->regs), - UPT_SYSCALL_ARG1(®s->regs), - UPT_SYSCALL_ARG2(®s->regs), - UPT_SYSCALL_ARG3(®s->regs), - UPT_SYSCALL_ARG4(®s->regs)); - else - audit_syscall_exit(current, - UPT_SYSCALL_RET(®s->regs)); + audit_syscall_entry(current, + HOST_AUDIT_ARCH, + UPT_SYSCALL_NR(regs), + UPT_SYSCALL_ARG1(regs), + UPT_SYSCALL_ARG2(regs), + UPT_SYSCALL_ARG3(regs), + UPT_SYSCALL_ARG4(regs)); + else { + int res = UPT_SYSCALL_RET(regs); + audit_syscall_exit(current, AUDITSC_RESULT(res), + res); + } } /* Fake a debug trap */ diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c index c64b9c97c74..e26e86bb56f 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c @@ -635,20 +635,29 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs) /* do the secure computing check first */ secure_computing(regs->orig_rax); - if (unlikely(current->audit_context)) - audit_syscall_entry(current, regs->orig_rax, - regs->rdi, regs->rsi, - regs->rdx, regs->r10); - if (test_thread_flag(TIF_SYSCALL_TRACE) && (current->ptrace & PT_PTRACED)) syscall_trace(regs); + + if (unlikely(current->audit_context)) { + if (test_thread_flag(TIF_IA32)) { + audit_syscall_entry(current, AUDIT_ARCH_I386, + regs->orig_rax, + regs->rbx, regs->rcx, + regs->rdx, regs->rsi); + } else { + audit_syscall_entry(current, AUDIT_ARCH_X86_64, + regs->orig_rax, + regs->rdi, regs->rsi, + regs->rdx, regs->r10); + } + } } asmlinkage void syscall_trace_leave(struct pt_regs *regs) { if (unlikely(current->audit_context)) - audit_syscall_exit(current, regs->rax); + audit_syscall_exit(current, AUDITSC_RESULT(regs->rax), regs->rax); if ((test_thread_flag(TIF_SYSCALL_TRACE) || test_thread_flag(TIF_SINGLESTEP)) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index f4fa27315fb..2b3902c867d 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -405,9 +405,8 @@ void device_release_driver(struct device * dev) static void driver_detach(struct device_driver * drv) { - struct list_head * entry, * next; - list_for_each_safe(entry, next, &drv->devices) { - struct device * dev = container_of(entry, struct device, driver_list); + while (!list_empty(&drv->devices)) { + struct device * dev = container_of(drv->devices.next, struct device, driver_list); device_release_driver(dev); } } diff --git a/drivers/base/core.c b/drivers/base/core.c index a7cedd8cefe..268a9c8d168 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -139,7 +139,7 @@ static int dev_hotplug(struct kset *kset, struct kobject *kobj, char **envp, buffer = &buffer[length]; buffer_size -= length; - if (dev->bus->hotplug) { + if (dev->bus && dev->bus->hotplug) { /* have the bus specific function add its stuff */ retval = dev->bus->hotplug (dev, envp, num_envp, buffer, buffer_size); if (retval) { diff --git a/fs/namei.c b/fs/namei.c index 9e4aef2a1a2..0f76fd75591 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -686,11 +686,11 @@ fail: /* * Name resolution. + * This is the basic name resolution function, turning a pathname into + * the final dentry. We expect 'base' to be positive and a directory. * - * This is the basic name resolution function, turning a pathname - * into the final dentry. - * - * We expect 'base' to be positive and a directory. + * Returns 0 and nd will have valid dentry and mnt on success. + * Returns error and drops reference to input namei data on failure. */ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) { @@ -929,8 +929,10 @@ int fastcall path_walk(const char * name, struct nameidata *nd) return link_path_walk(name, nd); } -/* SMP-safe */ -/* returns 1 if everything is done */ +/* + * SMP-safe: Returns 1 and nd will have valid dentry and mnt, if + * everything is done. Returns 0 and drops input nd, if lookup failed; + */ static int __emul_lookup_dentry(const char *name, struct nameidata *nd) { if (path_walk(name, nd)) @@ -994,9 +996,10 @@ set_it: } } +/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd) { - int retval; + int retval = 0; nd->last_type = LAST_ROOT; /* if there are only slashes... */ nd->flags = flags; @@ -1009,7 +1012,7 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata nd->dentry = dget(current->fs->altroot); read_unlock(¤t->fs->lock); if (__emul_lookup_dentry(name,nd)) - return 0; + goto out; /* found in altroot */ read_lock(¤t->fs->lock); } nd->mnt = mntget(current->fs->rootmnt); @@ -1021,6 +1024,7 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata read_unlock(¤t->fs->lock); current->total_link_count = 0; retval = link_path_walk(name, nd); +out: if (unlikely(current->audit_context && nd && nd->dentry && nd->dentry->d_inode)) audit_inode(name, nd->dentry->d_inode); diff --git a/fs/proc/base.c b/fs/proc/base.c index 07cafdf74ef..e31903aadd9 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -820,7 +820,7 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf, goto out_free_page; } - length = audit_set_loginuid(task->audit_context, loginuid); + length = audit_set_loginuid(task, loginuid); if (likely(length == 0)) length = count; diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 554e4a18c15..d3ff7835463 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -49,7 +49,7 @@ ifeq ($(CONFIG_XFS_TRACE),y) EXTRA_CFLAGS += -DXFS_LOG_TRACE EXTRA_CFLAGS += -DXFS_RW_TRACE EXTRA_CFLAGS += -DPAGEBUF_TRACE - # EXTRA_CFLAGS += -DXFS_VNODE_TRACE + EXTRA_CFLAGS += -DXFS_VNODE_TRACE endif obj-$(CONFIG_XFS_FS) += xfs.o diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 76a84758073..9278e9aba9b 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -558,7 +558,8 @@ xfs_submit_page( int i; BUG_ON(PageWriteback(page)); - set_page_writeback(page); + if (bh_count) + set_page_writeback(page); if (clear_dirty) clear_page_dirty(page); unlock_page(page); @@ -578,9 +579,6 @@ xfs_submit_page( if (probed_page && clear_dirty) wbc->nr_to_write--; /* Wrote an "extra" page */ - } else { - end_page_writeback(page); - wbc->pages_skipped++; /* We didn't write this page */ } } @@ -602,21 +600,26 @@ xfs_convert_page( { struct buffer_head *bh_arr[MAX_BUF_PER_PAGE], *bh, *head; xfs_iomap_t *mp = iomapp, *tmp; - unsigned long end, offset; - pgoff_t end_index; - int i = 0, index = 0; + unsigned long offset, end_offset; + int index = 0; int bbits = inode->i_blkbits; + int len, page_dirty; - end_index = i_size_read(inode) >> PAGE_CACHE_SHIFT; - if (page->index < end_index) { - end = PAGE_CACHE_SIZE; - } else { - end = i_size_read(inode) & (PAGE_CACHE_SIZE-1); - } + end_offset = (i_size_read(inode) & (PAGE_CACHE_SIZE - 1)); + + /* + * page_dirty is initially a count of buffers on the page before + * EOF and is decrememted as we move each into a cleanable state. + */ + len = 1 << inode->i_blkbits; + end_offset = max(end_offset, PAGE_CACHE_SIZE); + end_offset = roundup(end_offset, len); + page_dirty = end_offset / len; + + offset = 0; bh = head = page_buffers(page); do { - offset = i << bbits; - if (offset >= end) + if (offset >= end_offset) break; if (!(PageUptodate(page) || buffer_uptodate(bh))) continue; @@ -625,6 +628,7 @@ xfs_convert_page( if (startio) { lock_buffer(bh); bh_arr[index++] = bh; + page_dirty--; } continue; } @@ -657,10 +661,11 @@ xfs_convert_page( unlock_buffer(bh); mark_buffer_dirty(bh); } - } while (i++, (bh = bh->b_this_page) != head); + page_dirty--; + } while (offset += len, (bh = bh->b_this_page) != head); - if (startio) { - xfs_submit_page(page, wbc, bh_arr, index, 1, index == i); + if (startio && index) { + xfs_submit_page(page, wbc, bh_arr, index, 1, !page_dirty); } else { unlock_page(page); } @@ -725,8 +730,11 @@ xfs_page_state_convert( __uint64_t end_offset; pgoff_t end_index, last_index, tlast; int len, err, i, cnt = 0, uptodate = 1; - int flags = startio ? 0 : BMAPI_TRYLOCK; - int page_dirty, delalloc = 0; + int flags; + int page_dirty; + + /* wait for other IO threads? */ + flags = (startio && wbc->sync_mode != WB_SYNC_NONE) ? 0 : BMAPI_TRYLOCK; /* Is this page beyond the end of the file? */ offset = i_size_read(inode); @@ -740,19 +748,22 @@ xfs_page_state_convert( } } - offset = (loff_t)page->index << PAGE_CACHE_SHIFT; end_offset = min_t(unsigned long long, - offset + PAGE_CACHE_SIZE, i_size_read(inode)); - - bh = head = page_buffers(page); - iomp = NULL; + (loff_t)(page->index + 1) << PAGE_CACHE_SHIFT, offset); + offset = (loff_t)page->index << PAGE_CACHE_SHIFT; /* - * page_dirty is initially a count of buffers on the page and - * is decrememted as we move each into a cleanable state. + * page_dirty is initially a count of buffers on the page before + * EOF and is decrememted as we move each into a cleanable state. */ - len = bh->b_size; - page_dirty = PAGE_CACHE_SIZE / len; + len = 1 << inode->i_blkbits; + p_offset = max(p_offset, PAGE_CACHE_SIZE); + p_offset = roundup(p_offset, len); + page_dirty = p_offset / len; + + iomp = NULL; + p_offset = 0; + bh = head = page_buffers(page); do { if (offset >= end_offset) @@ -804,7 +815,6 @@ xfs_page_state_convert( */ } else if (buffer_delay(bh)) { if (!iomp) { - delalloc = 1; err = xfs_map_blocks(inode, offset, len, &iomap, BMAPI_ALLOCATE | flags); if (err) { @@ -875,14 +885,15 @@ xfs_page_state_convert( if (uptodate && bh == head) SetPageUptodate(page); - if (startio) - xfs_submit_page(page, wbc, bh_arr, cnt, 0, 1); + if (startio) { + WARN_ON(page_dirty); + xfs_submit_page(page, wbc, bh_arr, cnt, 0, !page_dirty); + } if (iomp) { - tlast = (iomp->iomap_offset + iomp->iomap_bsize - 1) >> + offset = (iomp->iomap_offset + iomp->iomap_bsize - 1) >> PAGE_CACHE_SHIFT; - if (delalloc && (tlast > last_index)) - tlast = last_index; + tlast = min_t(pgoff_t, offset, last_index); xfs_cluster_write(inode, page->index + 1, iomp, wbc, startio, unmapped, tlast); } diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 23e0eb67fc2..997963e5362 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1746,13 +1746,15 @@ STATIC DECLARE_COMPLETION(pagebuf_daemon_done); STATIC struct task_struct *pagebuf_daemon_task; STATIC int pagebuf_daemon_active; STATIC int force_flush; - +STATIC int force_sleep; STATIC int pagebuf_daemon_wakeup( int priority, unsigned int mask) { + if (force_sleep) + return 0; force_flush = 1; barrier(); wake_up_process(pagebuf_daemon_task); @@ -1778,7 +1780,12 @@ pagebuf_daemon( INIT_LIST_HEAD(&tmp); do { - try_to_freeze(PF_FREEZE); + if (unlikely(current->flags & PF_FREEZE)) { + force_sleep = 1; + refrigerator(PF_FREEZE); + } else { + force_sleep = 0; + } set_current_state(TASK_INTERRUPTIBLE); schedule_timeout((xfs_buf_timer_centisecs * HZ) / 100); diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 9f057a4a5b0..d0d412afd26 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c @@ -515,10 +515,49 @@ open_exec_out: } #endif /* HAVE_FOP_OPEN_EXEC */ +/* + * Temporary workaround to the AIO direct IO write problem. + * This code can go and we can revert to do_sync_write once + * the writepage(s) rework is merged. + */ +STATIC ssize_t +linvfs_write( + struct file *filp, + const char __user *buf, + size_t len, + loff_t *ppos) +{ + struct kiocb kiocb; + ssize_t ret; + + init_sync_kiocb(&kiocb, filp); + kiocb.ki_pos = *ppos; + ret = __linvfs_write(&kiocb, buf, 0, len, kiocb.ki_pos); + *ppos = kiocb.ki_pos; + return ret; +} +STATIC ssize_t +linvfs_write_invis( + struct file *filp, + const char __user *buf, + size_t len, + loff_t *ppos) +{ + struct kiocb kiocb; + ssize_t ret; + + init_sync_kiocb(&kiocb, filp); + kiocb.ki_pos = *ppos; + ret = __linvfs_write(&kiocb, buf, IO_INVIS, len, kiocb.ki_pos); + *ppos = kiocb.ki_pos; + return ret; +} + + struct file_operations linvfs_file_operations = { .llseek = generic_file_llseek, .read = do_sync_read, - .write = do_sync_write, + .write = linvfs_write, .readv = linvfs_readv, .writev = linvfs_writev, .aio_read = linvfs_aio_read, @@ -540,7 +579,7 @@ struct file_operations linvfs_file_operations = { struct file_operations linvfs_invis_file_operations = { .llseek = generic_file_llseek, .read = do_sync_read, - .write = do_sync_write, + .write = linvfs_write_invis, .readv = linvfs_readv_invis, .writev = linvfs_writev_invis, .aio_read = linvfs_aio_read_invis, diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index ff145fd0d1a..aa9daaea6c3 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c @@ -683,6 +683,9 @@ xfs_write( (xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? mp->m_rtdev_targp : mp->m_ddev_targp; + if (ioflags & IO_ISAIO) + return XFS_ERROR(-ENOSYS); + if ((pos & target->pbr_smask) || (count & target->pbr_smask)) return XFS_ERROR(-EINVAL); diff --git a/fs/xfs/linux-2.6/xfs_vnode.c b/fs/xfs/linux-2.6/xfs_vnode.c index 849c61c74f3..a832d165f24 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.c +++ b/fs/xfs/linux-2.6/xfs_vnode.c @@ -156,7 +156,6 @@ vn_initialize( #ifdef XFS_VNODE_TRACE vp->v_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP); - printk("Allocated VNODE_TRACE at 0x%p\n", vp->v_trace); #endif /* XFS_VNODE_TRACE */ vn_trace_exit(vp, "vn_initialize", (inst_t *)__return_address); @@ -424,13 +423,13 @@ vn_remove( * Vnode tracing code. */ void -vn_trace_entry(vnode_t *vp, char *func, inst_t *ra) +vn_trace_entry(vnode_t *vp, const char *func, inst_t *ra) { KTRACE_ENTER(vp, VNODE_KTRACE_ENTRY, func, 0, ra); } void -vn_trace_exit(vnode_t *vp, char *func, inst_t *ra) +vn_trace_exit(vnode_t *vp, const char *func, inst_t *ra) { KTRACE_ENTER(vp, VNODE_KTRACE_EXIT, func, 0, ra); } diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h index da76c1f1e11..00466c3194a 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h @@ -86,10 +86,11 @@ typedef struct vnode { vnumber_t v_number; /* in-core vnode number */ vn_bhv_head_t v_bh; /* behavior head */ spinlock_t v_lock; /* VN_LOCK/VN_UNLOCK */ - struct inode v_inode; /* Linux inode */ #ifdef XFS_VNODE_TRACE struct ktrace *v_trace; /* trace header structure */ #endif + struct inode v_inode; /* Linux inode */ + /* inode MUST be last */ } vnode_t; #define v_fbhv v_bh.bh_first /* first behavior */ @@ -409,7 +410,7 @@ typedef struct vattr { int va_mask; /* bit-mask of attributes present */ enum vtype va_type; /* vnode type (for create) */ mode_t va_mode; /* file access mode and type */ - nlink_t va_nlink; /* number of references to file */ + xfs_nlink_t va_nlink; /* number of references to file */ uid_t va_uid; /* owner user id */ gid_t va_gid; /* owner group id */ xfs_ino_t va_nodeid; /* file id */ @@ -625,6 +626,7 @@ static inline int VN_BAD(struct vnode *vp) #define ATTR_DMI 0x08 /* invocation from a DMI function */ #define ATTR_LAZY 0x80 /* set/get attributes lazily */ #define ATTR_NONBLOCK 0x100 /* return EAGAIN if operation would block */ +#define ATTR_NOLOCK 0x200 /* Don't grab any conflicting locks */ /* * Flags to VOP_FSYNC and VOP_RECLAIM. @@ -646,8 +648,8 @@ static inline int VN_BAD(struct vnode *vp) #define VNODE_KTRACE_REF 4 #define VNODE_KTRACE_RELE 5 -extern void vn_trace_entry(struct vnode *, char *, inst_t *); -extern void vn_trace_exit(struct vnode *, char *, inst_t *); +extern void vn_trace_entry(struct vnode *, const char *, inst_t *); +extern void vn_trace_exit(struct vnode *, const char *, inst_t *); extern void vn_trace_hold(struct vnode *, char *, int, inst_t *); extern void vn_trace_ref(struct vnode *, char *, int, inst_t *); extern void vn_trace_rele(struct vnode *, char *, int, inst_t *); diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c index 08d551a1734..63abdc2ac7f 100644 --- a/fs/xfs/xfs_dfrag.c +++ b/fs/xfs/xfs_dfrag.c @@ -182,7 +182,7 @@ xfs_swapext( if (VN_CACHED(tvp) != 0) xfs_inval_cached_pages(XFS_ITOV(tip), &(tip->i_iocore), - (loff_t)0, 0, 0); + (xfs_off_t)0, 0, 0); /* Verify O_DIRECT for ftmp */ if (VN_CACHED(tvp) != 0) { diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 3a0ba1dfd0e..d3da00045f2 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -136,6 +136,40 @@ xfs_chash_free(xfs_mount_t *mp) } /* + * Try to move an inode to the front of its hash list if possible + * (and if its not there already). Called right after obtaining + * the list version number and then dropping the read_lock on the + * hash list in question (which is done right after looking up the + * inode in question...). + */ +STATIC void +xfs_ihash_promote( + xfs_ihash_t *ih, + xfs_inode_t *ip, + ulong version) +{ + xfs_inode_t *iq; + + if ((ip->i_prevp != &ih->ih_next) && write_trylock(&ih->ih_lock)) { + if (likely(version == ih->ih_version)) { + /* remove from list */ + if ((iq = ip->i_next)) { + iq->i_prevp = ip->i_prevp; + } + *ip->i_prevp = iq; + + /* insert at list head */ + iq = ih->ih_next; + iq->i_prevp = &ip->i_next; + ip->i_next = iq; + ip->i_prevp = &ih->ih_next; + ih->ih_next = ip; + } + write_unlock(&ih->ih_lock); + } +} + +/* * Look up an inode by number in the given file system. * The inode is looked up in the hash table for the file system * represented by the mount point parameter mp. Each bucket of @@ -229,7 +263,9 @@ again: XFS_STATS_INC(xs_ig_found); ip->i_flags &= ~XFS_IRECLAIMABLE; + version = ih->ih_version; read_unlock(&ih->ih_lock); + xfs_ihash_promote(ih, ip, version); XFS_MOUNT_ILOCK(mp); list_del_init(&ip->i_reclaim); @@ -259,8 +295,15 @@ again: inode_vp, vp); } + /* + * Inode cache hit: if ip is not at the front of + * its hash chain, move it there now. + * Do this with the lock held for update, but + * do statistics after releasing the lock. + */ + version = ih->ih_version; read_unlock(&ih->ih_lock); - + xfs_ihash_promote(ih, ip, version); XFS_STATS_INC(xs_ig_found); finish_inode: @@ -547,6 +590,7 @@ xfs_inode_incore(xfs_mount_t *mp, { xfs_ihash_t *ih; xfs_inode_t *ip; + ulong version; ih = XFS_IHASH(mp, ino); read_lock(&ih->ih_lock); @@ -554,11 +598,15 @@ xfs_inode_incore(xfs_mount_t *mp, if (ip->i_ino == ino) { /* * If we find it and tp matches, return it. + * Also move it to the front of the hash list + * if we find it and it is not already there. * Otherwise break from the loop and return * NULL. */ if (ip->i_transp == tp) { + version = ih->ih_version; read_unlock(&ih->ih_lock); + xfs_ihash_promote(ih, ip, version); return (ip); } break; @@ -685,6 +733,7 @@ xfs_iextract( iq->i_prevp = ip->i_prevp; } *ip->i_prevp = iq; + ih->ih_version++; write_unlock(&ih->ih_lock); /* diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 43c632ab86a..bc8c8c7f903 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1130,7 +1130,7 @@ xfs_ialloc( xfs_trans_t *tp, xfs_inode_t *pip, mode_t mode, - nlink_t nlink, + xfs_nlink_t nlink, xfs_dev_t rdev, cred_t *cr, xfs_prid_t prid, diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index a53b1ccf607..37e1c316f3b 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -495,9 +495,9 @@ int xfs_itobp(struct xfs_mount *, struct xfs_trans *, int xfs_iread(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, xfs_inode_t **, xfs_daddr_t); int xfs_iread_extents(struct xfs_trans *, xfs_inode_t *, int); -int xfs_ialloc(struct xfs_trans *, xfs_inode_t *, mode_t, nlink_t, - xfs_dev_t, struct cred *, xfs_prid_t, int, - struct xfs_buf **, boolean_t *, xfs_inode_t **); +int xfs_ialloc(struct xfs_trans *, xfs_inode_t *, mode_t, + xfs_nlink_t, xfs_dev_t, struct cred *, xfs_prid_t, + int, struct xfs_buf **, boolean_t *, xfs_inode_t **); void xfs_xlate_dinode_core(xfs_caddr_t, struct xfs_dinode_core *, int); uint xfs_ip2xflags(struct xfs_inode *); diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 3826e8f0e28..991f8a61f7c 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -308,7 +308,8 @@ phase2: break; } - error = XFS_IOMAP_WRITE_ALLOCATE(mp, io, &imap, &nimaps); + error = XFS_IOMAP_WRITE_ALLOCATE(mp, io, offset, count, + &imap, &nimaps); break; case BMAPI_UNWRITTEN: lockmode = 0; @@ -365,7 +366,7 @@ xfs_flush_space( int xfs_iomap_write_direct( xfs_inode_t *ip, - loff_t offset, + xfs_off_t offset, size_t count, int flags, xfs_bmbt_irec_t *ret_imap, @@ -541,7 +542,7 @@ error_out: int xfs_iomap_write_delay( xfs_inode_t *ip, - loff_t offset, + xfs_off_t offset, size_t count, int ioflag, xfs_bmbt_irec_t *ret_imap, @@ -746,6 +747,8 @@ write_map: int xfs_iomap_write_allocate( xfs_inode_t *ip, + xfs_off_t offset, + size_t count, xfs_bmbt_irec_t *map, int *retmap) { @@ -770,9 +773,9 @@ xfs_iomap_write_allocate( if ((error = XFS_QM_DQATTACH(mp, ip, 0))) return XFS_ERROR(error); - offset_fsb = map->br_startoff; + offset_fsb = XFS_B_TO_FSBT(mp, offset); count_fsb = map->br_blockcount; - map_start_fsb = offset_fsb; + map_start_fsb = map->br_startoff; XFS_STATS_ADD(xs_xstrat_bytes, XFS_FSB_TO_B(mp, count_fsb)); @@ -868,9 +871,9 @@ xfs_iomap_write_allocate( imap[i].br_startoff, imap[i].br_blockcount,imap[i].br_state); } - if ((map->br_startoff >= imap[i].br_startoff) && - (map->br_startoff < (imap[i].br_startoff + - imap[i].br_blockcount))) { + if ((offset_fsb >= imap[i].br_startoff) && + (offset_fsb < (imap[i].br_startoff + + imap[i].br_blockcount))) { *map = imap[i]; *retmap = 1; XFS_STATS_INC(xs_xstrat_quick); @@ -883,9 +886,8 @@ xfs_iomap_write_allocate( * file, just surrounding data, try again. */ nimaps--; - offset_fsb = imap[nimaps].br_startoff + - imap[nimaps].br_blockcount; - map_start_fsb = offset_fsb; + map_start_fsb = imap[nimaps].br_startoff + + imap[nimaps].br_blockcount; } trans_cancel: @@ -899,7 +901,7 @@ error0: int xfs_iomap_write_unwritten( xfs_inode_t *ip, - loff_t offset, + xfs_off_t offset, size_t count) { xfs_mount_t *mp = ip->i_mount; diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h index 31c91087cb3..4daaa521210 100644 --- a/fs/xfs/xfs_iomap.h +++ b/fs/xfs/xfs_iomap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003,2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2003-2005 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -29,9 +29,6 @@ * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ - - - #ifndef __XFS_IOMAP_H__ #define __XFS_IOMAP_H__ @@ -56,7 +53,7 @@ typedef enum { BMAPI_UNWRITTEN = (1 << 3), /* unwritten extents to real extents */ /* modifiers */ BMAPI_IGNSTATE = (1 << 4), /* ignore unwritten state on read */ - BMAPI_DIRECT = (1 << 5), /* direct instead of buffered write */ + BMAPI_DIRECT = (1 << 5), /* direct instead of buffered write */ BMAPI_MMAP = (1 << 6), /* allocate for mmap write */ BMAPI_SYNC = (1 << 7), /* sync write to flush delalloc space */ BMAPI_TRYLOCK = (1 << 8), /* non-blocking request */ @@ -67,13 +64,13 @@ typedef enum { /* * xfs_iomap_t: File system I/O map * - * The iomap_bn field is expressed in 512-byte blocks, and is where the + * The iomap_bn field is expressed in 512-byte blocks, and is where the * mapping starts on disk. * * The iomap_offset, iomap_bsize and iomap_delta fields are in bytes. * iomap_offset is the offset of the mapping in the file itself. - * iomap_bsize is the size of the mapping, iomap_delta is the - * desired data's offset into the mapping, given the offset supplied + * iomap_bsize is the size of the mapping, iomap_delta is the + * desired data's offset into the mapping, given the offset supplied * to the file I/O map routine. * * When a request is made to read beyond the logical end of the object, @@ -84,8 +81,8 @@ typedef enum { typedef struct xfs_iomap { xfs_daddr_t iomap_bn; /* first 512b blk of mapping */ xfs_buftarg_t *iomap_target; - loff_t iomap_offset; /* offset of mapping, bytes */ - loff_t iomap_bsize; /* size of mapping, bytes */ + xfs_off_t iomap_offset; /* offset of mapping, bytes */ + xfs_off_t iomap_bsize; /* size of mapping, bytes */ size_t iomap_delta; /* offset into mapping, bytes */ iomap_flags_t iomap_flags; } xfs_iomap_t; @@ -96,12 +93,12 @@ struct xfs_bmbt_irec; extern int xfs_iomap(struct xfs_iocore *, xfs_off_t, ssize_t, int, struct xfs_iomap *, int *); -extern int xfs_iomap_write_direct(struct xfs_inode *, loff_t, size_t, +extern int xfs_iomap_write_direct(struct xfs_inode *, xfs_off_t, size_t, int, struct xfs_bmbt_irec *, int *, int); -extern int xfs_iomap_write_delay(struct xfs_inode *, loff_t, size_t, int, +extern int xfs_iomap_write_delay(struct xfs_inode *, xfs_off_t, size_t, int, struct xfs_bmbt_irec *, int *); -extern int xfs_iomap_write_allocate(struct xfs_inode *, +extern int xfs_iomap_write_allocate(struct xfs_inode *, xfs_off_t, size_t, struct xfs_bmbt_irec *, int *); -extern int xfs_iomap_write_unwritten(struct xfs_inode *, loff_t, size_t); +extern int xfs_iomap_write_unwritten(struct xfs_inode *, xfs_off_t, size_t); #endif /* __XFS_IOMAP_H__*/ diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index b57423caef9..2ec967d93e5 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -301,6 +301,15 @@ xfs_mount_validate_sb( } /* + * Version 1 directory format has never worked on Linux. + */ + if (unlikely(!XFS_SB_VERSION_HASDIRV2(sbp))) { + cmn_err(CE_WARN, + "XFS: Attempted to mount file system using version 1 directory format"); + return XFS_ERROR(ENOSYS); + } + + /* * Until this is fixed only page-sized or smaller data blocks work. */ if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) { diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 5fc6201dd8e..30dd08fb9f5 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -210,15 +210,16 @@ typedef int (*xfs_bmapi_t)(struct xfs_trans *, void *, struct xfs_bmap_free *); typedef int (*xfs_bmap_eof_t)(void *, xfs_fileoff_t, int, int *); typedef int (*xfs_iomap_write_direct_t)( - void *, loff_t, size_t, int, + void *, xfs_off_t, size_t, int, struct xfs_bmbt_irec *, int *, int); typedef int (*xfs_iomap_write_delay_t)( - void *, loff_t, size_t, int, + void *, xfs_off_t, size_t, int, struct xfs_bmbt_irec *, int *); typedef int (*xfs_iomap_write_allocate_t)( - void *, struct xfs_bmbt_irec *, int *); + void *, xfs_off_t, size_t, + struct xfs_bmbt_irec *, int *); typedef int (*xfs_iomap_write_unwritten_t)( - void *, loff_t, size_t); + void *, xfs_off_t, size_t); typedef uint (*xfs_lck_map_shared_t)(void *); typedef void (*xfs_lock_t)(void *, uint); typedef void (*xfs_lock_demote_t)(void *, uint); @@ -258,9 +259,9 @@ typedef struct xfs_ioops { #define XFS_IOMAP_WRITE_DELAY(mp, io, offset, count, flags, mval, nmap) \ (*(mp)->m_io_ops.xfs_iomap_write_delay) \ ((io)->io_obj, offset, count, flags, mval, nmap) -#define XFS_IOMAP_WRITE_ALLOCATE(mp, io, mval, nmap) \ +#define XFS_IOMAP_WRITE_ALLOCATE(mp, io, offset, count, mval, nmap) \ (*(mp)->m_io_ops.xfs_iomap_write_allocate) \ - ((io)->io_obj, mval, nmap) + ((io)->io_obj, offset, count, mval, nmap) #define XFS_IOMAP_WRITE_UNWRITTEN(mp, io, offset, count) \ (*(mp)->m_io_ops.xfs_iomap_write_unwritten) \ ((io)->io_obj, offset, count) @@ -428,10 +429,10 @@ typedef struct xfs_mount { #define XFS_WRITEIO_LOG_LARGE 16 /* - * Max and min values for UIO and mount-option defined I/O sizes; - * min value can't be less than a page. Currently unused. + * Max and min values for mount-option defined I/O + * preallocation sizes. */ -#define XFS_MAX_IO_LOG 16 /* 64K */ +#define XFS_MAX_IO_LOG 30 /* 1G */ #define XFS_MIN_IO_LOG PAGE_SHIFT /* diff --git a/fs/xfs/xfs_types.h b/fs/xfs/xfs_types.h index 04609d27ea5..e4bf711e48f 100644 --- a/fs/xfs/xfs_types.h +++ b/fs/xfs/xfs_types.h @@ -63,6 +63,7 @@ typedef __u64 xfs_ino_t; /* <inode> type */ typedef __s64 xfs_daddr_t; /* <disk address> type */ typedef char * xfs_caddr_t; /* <core address> type */ typedef __u32 xfs_dev_t; +typedef __u32 xfs_nlink_t; /* __psint_t is the same size as a pointer */ #if (BITS_PER_LONG == 32) diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c index 816b945fa0e..d1f8146a06e 100644 --- a/fs/xfs/xfs_utils.c +++ b/fs/xfs/xfs_utils.c @@ -147,7 +147,7 @@ xfs_dir_ialloc( xfs_inode_t *dp, /* directory within whose allocate the inode. */ mode_t mode, - nlink_t nlink, + xfs_nlink_t nlink, xfs_dev_t rdev, cred_t *credp, prid_t prid, /* project id */ diff --git a/fs/xfs/xfs_utils.h b/fs/xfs/xfs_utils.h index e1ed6a58800..01d98b4b7af 100644 --- a/fs/xfs/xfs_utils.h +++ b/fs/xfs/xfs_utils.h @@ -42,7 +42,7 @@ extern int xfs_get_dir_entry (vname_t *, xfs_inode_t **); extern int xfs_dir_lookup_int (bhv_desc_t *, uint, vname_t *, xfs_ino_t *, xfs_inode_t **); extern int xfs_truncate_file (xfs_mount_t *, xfs_inode_t *); -extern int xfs_dir_ialloc (xfs_trans_t **, xfs_inode_t *, mode_t, nlink_t, +extern int xfs_dir_ialloc (xfs_trans_t **, xfs_inode_t *, mode_t, xfs_nlink_t, xfs_dev_t, cred_t *, prid_t, int, xfs_inode_t **, int *); extern int xfs_droplink (xfs_trans_t *, xfs_inode_t *); diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index 00aae9c6a90..b5373665010 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c @@ -1649,6 +1649,7 @@ xfs_vget( #define MNTOPT_SWIDTH "swidth" /* data volume stripe width */ #define MNTOPT_NOUUID "nouuid" /* ignore filesystem UUID */ #define MNTOPT_MTPT "mtpt" /* filesystem mount point */ +#define MNTOPT_ALLOCSIZE "allocsize" /* preferred allocation size */ #define MNTOPT_IHASHSIZE "ihashsize" /* size of inode hash table */ #define MNTOPT_NORECOVERY "norecovery" /* don't run XFS recovery */ #define MNTOPT_NOLOGFLUSH "nologflush" /* don't hard flush on log writes */ @@ -1657,6 +1658,28 @@ xfs_vget( #define MNTOPT_IKEEP "ikeep" /* do not free empty inode clusters */ #define MNTOPT_NOIKEEP "noikeep" /* free empty inode clusters */ +STATIC unsigned long +suffix_strtoul(const char *cp, char **endp, unsigned int base) +{ + int last, shift_left_factor = 0; + char *value = (char *)cp; + + last = strlen(value) - 1; + if (value[last] == 'K' || value[last] == 'k') { + shift_left_factor = 10; + value[last] = '\0'; + } + if (value[last] == 'M' || value[last] == 'm') { + shift_left_factor = 20; + value[last] = '\0'; + } + if (value[last] == 'G' || value[last] == 'g') { + shift_left_factor = 30; + value[last] = '\0'; + } + + return simple_strtoul(cp, endp, base) << shift_left_factor; +} int xfs_parseargs( @@ -1688,60 +1711,60 @@ xfs_parseargs( if (!strcmp(this_char, MNTOPT_LOGBUFS)) { if (!value || !*value) { printk("XFS: %s option requires an argument\n", - MNTOPT_LOGBUFS); + this_char); return EINVAL; } args->logbufs = simple_strtoul(value, &eov, 10); } else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) { - int last, in_kilobytes = 0; - if (!value || !*value) { printk("XFS: %s option requires an argument\n", - MNTOPT_LOGBSIZE); + this_char); return EINVAL; } - last = strlen(value) - 1; - if (value[last] == 'K' || value[last] == 'k') { - in_kilobytes = 1; - value[last] = '\0'; - } - args->logbufsize = simple_strtoul(value, &eov, 10); - if (in_kilobytes) - args->logbufsize <<= 10; + args->logbufsize = suffix_strtoul(value, &eov, 10); } else if (!strcmp(this_char, MNTOPT_LOGDEV)) { if (!value || !*value) { printk("XFS: %s option requires an argument\n", - MNTOPT_LOGDEV); + this_char); return EINVAL; } strncpy(args->logname, value, MAXNAMELEN); } else if (!strcmp(this_char, MNTOPT_MTPT)) { if (!value || !*value) { printk("XFS: %s option requires an argument\n", - MNTOPT_MTPT); + this_char); return EINVAL; } strncpy(args->mtpt, value, MAXNAMELEN); } else if (!strcmp(this_char, MNTOPT_RTDEV)) { if (!value || !*value) { printk("XFS: %s option requires an argument\n", - MNTOPT_RTDEV); + this_char); return EINVAL; } strncpy(args->rtname, value, MAXNAMELEN); } else if (!strcmp(this_char, MNTOPT_BIOSIZE)) { if (!value || !*value) { printk("XFS: %s option requires an argument\n", - MNTOPT_BIOSIZE); + this_char); return EINVAL; } iosize = simple_strtoul(value, &eov, 10); args->flags |= XFSMNT_IOSIZE; args->iosizelog = (uint8_t) iosize; + } else if (!strcmp(this_char, MNTOPT_ALLOCSIZE)) { + if (!value || !*value) { + printk("XFS: %s option requires an argument\n", + this_char); + return EINVAL; + } + iosize = suffix_strtoul(value, &eov, 10); + args->flags |= XFSMNT_IOSIZE; + args->iosizelog = ffs(iosize) - 1; } else if (!strcmp(this_char, MNTOPT_IHASHSIZE)) { if (!value || !*value) { printk("XFS: %s option requires an argument\n", - this_char); + this_char); return EINVAL; } args->flags |= XFSMNT_IHASHSIZE; @@ -1756,7 +1779,7 @@ xfs_parseargs( args->flags |= XFSMNT_INO64; #if !XFS_BIG_INUMS printk("XFS: %s option not allowed on this system\n", - MNTOPT_INO64); + this_char); return EINVAL; #endif } else if (!strcmp(this_char, MNTOPT_NOALIGN)) { @@ -1766,14 +1789,14 @@ xfs_parseargs( } else if (!strcmp(this_char, MNTOPT_SUNIT)) { if (!value || !*value) { printk("XFS: %s option requires an argument\n", - MNTOPT_SUNIT); + this_char); return EINVAL; } dsunit = simple_strtoul(value, &eov, 10); } else if (!strcmp(this_char, MNTOPT_SWIDTH)) { if (!value || !*value) { printk("XFS: %s option requires an argument\n", - MNTOPT_SWIDTH); + this_char); return EINVAL; } dswidth = simple_strtoul(value, &eov, 10); @@ -1781,7 +1804,7 @@ xfs_parseargs( args->flags &= ~XFSMNT_32BITINODES; #if !XFS_BIG_INUMS printk("XFS: %s option not allowed on this system\n", - MNTOPT_64BITINODE); + this_char); return EINVAL; #endif } else if (!strcmp(this_char, MNTOPT_NOUUID)) { @@ -1877,7 +1900,7 @@ xfs_showargs( seq_printf(m, "," MNTOPT_IHASHSIZE "=%d", mp->m_ihsize); if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) - seq_printf(m, "," MNTOPT_BIOSIZE "=%d", mp->m_writeio_log); + seq_printf(m, "," MNTOPT_ALLOCSIZE "=%d", 1<<mp->m_writeio_log); if (mp->m_logbufs > 0) seq_printf(m, "," MNTOPT_LOGBUFS "=%d", mp->m_logbufs); diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 70092963ca9..25a526629b1 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -305,7 +305,7 @@ xfs_setattr( int mandlock_before, mandlock_after; struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; int file_owner; - int need_iolock = (flags & ATTR_DMI) == 0; + int need_iolock = 1; vp = BHV_TO_VNODE(bdp); vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); @@ -384,6 +384,9 @@ xfs_setattr( */ tp = NULL; lock_flags = XFS_ILOCK_EXCL; + ASSERT(flags & ATTR_NOLOCK ? flags & ATTR_DMI : 1); + if (flags & ATTR_NOLOCK) + need_iolock = 0; if (!(mask & XFS_AT_SIZE)) { if ((mask != (XFS_AT_CTIME|XFS_AT_ATIME|XFS_AT_MTIME)) || (mp->m_flags & XFS_MOUNT_WSYNC)) { @@ -4320,7 +4323,7 @@ xfs_free_file_space( int rt; xfs_fileoff_t startoffset_fsb; xfs_trans_t *tp; - int need_iolock = (attr_flags & ATTR_DMI) == 0; + int need_iolock = 1; vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address); mp = ip->i_mount; @@ -4348,8 +4351,12 @@ xfs_free_file_space( return(error); } + ASSERT(attr_flags & ATTR_NOLOCK ? attr_flags & ATTR_DMI : 1); + if (attr_flags & ATTR_NOLOCK) + need_iolock = 0; if (need_iolock) xfs_ilock(ip, XFS_IOLOCK_EXCL); + rounding = MAX((__uint8_t)(1 << mp->m_sb.sb_blocklog), (__uint8_t)NBPP); ilen = len + (offset & (rounding - 1)); diff --git a/include/asm-um/ptrace-i386.h b/include/asm-um/ptrace-i386.h index 9e47590ec29..04222f35c43 100644 --- a/include/asm-um/ptrace-i386.h +++ b/include/asm-um/ptrace-i386.h @@ -6,6 +6,8 @@ #ifndef __UM_PTRACE_I386_H #define __UM_PTRACE_I386_H +#define HOST_AUDIT_ARCH AUDIT_ARCH_I386 + #include "sysdep/ptrace.h" #include "asm/ptrace-generic.h" diff --git a/include/asm-um/ptrace-x86_64.h b/include/asm-um/ptrace-x86_64.h index c34be39b78b..be51219a8ff 100644 --- a/include/asm-um/ptrace-x86_64.h +++ b/include/asm-um/ptrace-x86_64.h @@ -14,6 +14,8 @@ #include "asm/ptrace-generic.h" #undef signal_fault +#define HOST_AUDIT_ARCH AUDIT_ARCH_X86_64 + void signal_fault(struct pt_regs_subarch *regs, void *frame, char *where); #define FS_BASE (21 * sizeof(unsigned long)) diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h index bffb577bc54..a10ea155907 100644 --- a/include/asm-um/thread_info.h +++ b/include/asm-um/thread_info.h @@ -72,12 +72,14 @@ static inline struct thread_info *current_thread_info(void) */ #define TIF_RESTART_BLOCK 4 #define TIF_MEMDIE 5 +#define TIF_SYSCALL_AUDIT 6 #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) -#define _TIF_RESTART_BLOCK (1 << TIF_RESTART_BLOCK) +#define _TIF_MEMDIE (1 << TIF_MEMDIE) +#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #endif diff --git a/include/linux/audit.h b/include/linux/audit.h index 3628f7cfb17..19f04b04979 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -1,4 +1,4 @@ -/* audit.h -- Auditing support -*- linux-c -*- +/* audit.h -- Auditing support * * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. @@ -24,6 +24,9 @@ #ifndef _LINUX_AUDIT_H_ #define _LINUX_AUDIT_H_ +#include <linux/sched.h> +#include <linux/elf.h> + /* Request and reply types */ #define AUDIT_GET 1000 /* Get status */ #define AUDIT_SET 1001 /* Set status (enable/disable/auditd) */ @@ -67,6 +70,7 @@ #define AUDIT_FSGID 8 #define AUDIT_LOGINUID 9 #define AUDIT_PERS 10 +#define AUDIT_ARCH 11 /* These are ONLY useful when checking * at syscall exit time (AUDIT_AT_EXIT). */ @@ -96,6 +100,38 @@ #define AUDIT_FAIL_PRINTK 1 #define AUDIT_FAIL_PANIC 2 +/* distinguish syscall tables */ +#define __AUDIT_ARCH_64BIT 0x80000000 +#define __AUDIT_ARCH_LE 0x40000000 +#define AUDIT_ARCH_ALPHA (EM_ALPHA|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_ARM (EM_ARM|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_ARMEB (EM_ARM) +#define AUDIT_ARCH_CRIS (EM_CRIS|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_FRV (EM_FRV) +#define AUDIT_ARCH_H8300 (EM_H8_300) +#define AUDIT_ARCH_I386 (EM_386|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_IA64 (EM_IA_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_M32R (EM_M32R) +#define AUDIT_ARCH_M68K (EM_68K) +#define AUDIT_ARCH_MIPS (EM_MIPS) +#define AUDIT_ARCH_MIPSEL (EM_MIPS|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_MIPS64 (EM_MIPS|__AUDIT_ARCH_64BIT) +#define AUDIT_ARCH_MIPSEL64 (EM_MIPS|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_PARISC (EM_PARISC) +#define AUDIT_ARCH_PARISC64 (EM_PARISC|__AUDIT_ARCH_64BIT) +#define AUDIT_ARCH_PPC (EM_PPC) +#define AUDIT_ARCH_PPC64 (EM_PPC64|__AUDIT_ARCH_64BIT) +#define AUDIT_ARCH_S390 (EM_S390) +#define AUDIT_ARCH_S390X (EM_S390|__AUDIT_ARCH_64BIT) +#define AUDIT_ARCH_SH (EM_SH) +#define AUDIT_ARCH_SHEL (EM_SH|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_SH64 (EM_SH|__AUDIT_ARCH_64BIT) +#define AUDIT_ARCH_SHEL64 (EM_SH|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_SPARC (EM_SPARC) +#define AUDIT_ARCH_SPARC64 (EM_SPARC64|__AUDIT_ARCH_64BIT) +#define AUDIT_ARCH_V850 (EM_V850|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_X86_64 (EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) + #ifndef __KERNEL__ struct audit_message { struct nlmsghdr nlh; @@ -129,32 +165,36 @@ struct audit_buffer; struct audit_context; struct inode; +#define AUDITSC_INVALID 0 +#define AUDITSC_SUCCESS 1 +#define AUDITSC_FAILURE 2 +#define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS ) #ifdef CONFIG_AUDITSYSCALL /* These are defined in auditsc.c */ /* Public API */ extern int audit_alloc(struct task_struct *task); extern void audit_free(struct task_struct *task); -extern void audit_syscall_entry(struct task_struct *task, +extern void audit_syscall_entry(struct task_struct *task, int arch, int major, unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3); -extern void audit_syscall_exit(struct task_struct *task, int return_code); +extern void audit_syscall_exit(struct task_struct *task, int failed, long return_code); extern void audit_getname(const char *name); extern void audit_putname(const char *name); extern void audit_inode(const char *name, const struct inode *inode); /* Private API (for audit.c only) */ extern int audit_receive_filter(int type, int pid, int uid, int seq, - void *data); + void *data, uid_t loginuid); extern void audit_get_stamp(struct audit_context *ctx, - struct timespec *t, int *serial); -extern int audit_set_loginuid(struct audit_context *ctx, uid_t loginuid); + struct timespec *t, unsigned int *serial); +extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid); extern uid_t audit_get_loginuid(struct audit_context *ctx); extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode); #else #define audit_alloc(t) ({ 0; }) #define audit_free(t) do { ; } while (0) -#define audit_syscall_entry(t,a,b,c,d,e) do { ; } while (0) -#define audit_syscall_exit(t,r) do { ; } while (0) +#define audit_syscall_entry(t,ta,a,b,c,d,e) do { ; } while (0) +#define audit_syscall_exit(t,f,r) do { ; } while (0) #define audit_getname(n) do { ; } while (0) #define audit_putname(n) do { ; } while (0) #define audit_inode(n,i) do { ; } while (0) @@ -174,11 +214,15 @@ extern void audit_log_format(struct audit_buffer *ab, const char *fmt, ...) __attribute__((format(printf,2,3))); extern void audit_log_end(struct audit_buffer *ab); +extern void audit_log_hex(struct audit_buffer *ab, + const unsigned char *buf, + size_t len); +extern void audit_log_untrustedstring(struct audit_buffer *ab, + const char *string); extern void audit_log_d_path(struct audit_buffer *ab, const char *prefix, struct dentry *dentry, struct vfsmount *vfsmnt); - /* Private API (for auditsc.c only) */ extern void audit_send_reply(int pid, int seq, int type, int done, int multi, @@ -190,6 +234,8 @@ extern void audit_log_lost(const char *message); #define audit_log_vformat(b,f,a) do { ; } while (0) #define audit_log_format(b,f,...) do { ; } while (0) #define audit_log_end(b) do { ; } while (0) +#define audit_log_hex(a,b,l) do { ; } while (0) +#define audit_log_untrustedstring(a,s) do { ; } while (0) #define audit_log_d_path(b,p,d,v) do { ; } while (0) #endif #endif diff --git a/include/linux/netlink.h b/include/linux/netlink.h index f731abdc1a2..b2738ac8bc9 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -110,6 +110,7 @@ struct netlink_skb_parms __u32 dst_pid; __u32 dst_groups; kernel_cap_t eff_cap; + __u32 loginuid; /* Login (audit) uid */ }; #define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb)) diff --git a/init/Kconfig b/init/Kconfig index 40d286d1d11..d920baed109 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -173,7 +173,7 @@ config AUDIT config AUDITSYSCALL bool "Enable system-call auditing support" - depends on AUDIT && (X86 || PPC64 || ARCH_S390 || IA64) + depends on AUDIT && (X86 || PPC64 || ARCH_S390 || IA64 || UML) default y if SECURITY_SELINUX help Enable low-overhead system-call auditing infrastructure that diff --git a/kernel/audit.c b/kernel/audit.c index ac26d4d960d..9c4f1af0c79 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1,4 +1,4 @@ -/* audit.c -- Auditing support -*- linux-c -*- +/* audit.c -- Auditing support * Gateway between the kernel (e.g., selinux) and the user-space audit daemon. * System-call specific features have moved to auditsc.c * @@ -38,7 +38,7 @@ * 6) Support low-overhead kernel-based filtering to minimize the * information that must be passed to user-space. * - * Example user-space utilities: http://people.redhat.com/faith/audit/ + * Example user-space utilities: http://people.redhat.com/sgrubb/audit/ */ #include <linux/init.h> @@ -142,7 +142,6 @@ struct audit_buffer { int total; int type; int pid; - int count; /* Times requeued */ }; void audit_set_type(struct audit_buffer *ab, int type) @@ -239,36 +238,36 @@ void audit_log_lost(const char *message) } -static int audit_set_rate_limit(int limit) +static int audit_set_rate_limit(int limit, uid_t loginuid) { int old = audit_rate_limit; audit_rate_limit = limit; - audit_log(current->audit_context, "audit_rate_limit=%d old=%d", - audit_rate_limit, old); + audit_log(NULL, "audit_rate_limit=%d old=%d by auid %u", + audit_rate_limit, old, loginuid); return old; } -static int audit_set_backlog_limit(int limit) +static int audit_set_backlog_limit(int limit, uid_t loginuid) { int old = audit_backlog_limit; audit_backlog_limit = limit; - audit_log(current->audit_context, "audit_backlog_limit=%d old=%d", - audit_backlog_limit, old); + audit_log(NULL, "audit_backlog_limit=%d old=%d by auid %u", + audit_backlog_limit, old, loginuid); return old; } -static int audit_set_enabled(int state) +static int audit_set_enabled(int state, uid_t loginuid) { int old = audit_enabled; if (state != 0 && state != 1) return -EINVAL; audit_enabled = state; - audit_log(current->audit_context, "audit_enabled=%d old=%d", - audit_enabled, old); + audit_log(NULL, "audit_enabled=%d old=%d by auid %u", + audit_enabled, old, loginuid); return old; } -static int audit_set_failure(int state) +static int audit_set_failure(int state, uid_t loginuid) { int old = audit_failure; if (state != AUDIT_FAIL_SILENT @@ -276,8 +275,8 @@ static int audit_set_failure(int state) && state != AUDIT_FAIL_PANIC) return -EINVAL; audit_failure = state; - audit_log(current->audit_context, "audit_failure=%d old=%d", - audit_failure, old); + audit_log(NULL, "audit_failure=%d old=%d by auid %u", + audit_failure, old, loginuid); return old; } @@ -344,6 +343,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) int err; struct audit_buffer *ab; u16 msg_type = nlh->nlmsg_type; + uid_t loginuid; /* loginuid of sender */ err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type); if (err) @@ -351,6 +351,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) pid = NETLINK_CREDS(skb)->pid; uid = NETLINK_CREDS(skb)->uid; + loginuid = NETLINK_CB(skb).loginuid; seq = nlh->nlmsg_seq; data = NLMSG_DATA(nlh); @@ -371,34 +372,36 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return -EINVAL; status_get = (struct audit_status *)data; if (status_get->mask & AUDIT_STATUS_ENABLED) { - err = audit_set_enabled(status_get->enabled); + err = audit_set_enabled(status_get->enabled, loginuid); if (err < 0) return err; } if (status_get->mask & AUDIT_STATUS_FAILURE) { - err = audit_set_failure(status_get->failure); + err = audit_set_failure(status_get->failure, loginuid); if (err < 0) return err; } if (status_get->mask & AUDIT_STATUS_PID) { int old = audit_pid; audit_pid = status_get->pid; - audit_log(current->audit_context, - "audit_pid=%d old=%d", audit_pid, old); + audit_log(NULL, "audit_pid=%d old=%d by auid %u", + audit_pid, old, loginuid); } if (status_get->mask & AUDIT_STATUS_RATE_LIMIT) - audit_set_rate_limit(status_get->rate_limit); + audit_set_rate_limit(status_get->rate_limit, loginuid); if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT) - audit_set_backlog_limit(status_get->backlog_limit); + audit_set_backlog_limit(status_get->backlog_limit, + loginuid); break; case AUDIT_USER: ab = audit_log_start(NULL); if (!ab) break; /* audit_panic has been called */ audit_log_format(ab, - "user pid=%d uid=%d length=%d msg='%.1024s'", + "user pid=%d uid=%d length=%d loginuid=%u" + " msg='%.1024s'", pid, uid, (int)(nlh->nlmsg_len - ((char *)data - (char *)nlh)), - (char *)data); + loginuid, (char *)data); ab->type = AUDIT_USER; ab->pid = pid; audit_log_end(ab); @@ -411,7 +414,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) case AUDIT_LIST: #ifdef CONFIG_AUDITSYSCALL err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, - uid, seq, data); + uid, seq, data, loginuid); #else err = -EOPNOTSUPP; #endif @@ -480,7 +483,7 @@ static void audit_log_move(struct audit_buffer *ab) if (ab->len == 0) return; - skb = skb_peek(&ab->sklist); + skb = skb_peek_tail(&ab->sklist); if (!skb || skb_tailroom(skb) <= ab->len + extra) { skb = alloc_skb(2 * ab->len + extra, GFP_ATOMIC); if (!skb) { @@ -519,9 +522,9 @@ static inline int audit_log_drain(struct audit_buffer *ab) retval = netlink_unicast(audit_sock, skb, audit_pid, MSG_DONTWAIT); } - if (retval == -EAGAIN && ab->count < 5) { - ++ab->count; - skb_queue_tail(&ab->sklist, skb); + if (retval == -EAGAIN && + (atomic_read(&audit_backlog)) < audit_backlog_limit) { + skb_queue_head(&ab->sklist, skb); audit_log_end_irq(ab); return 1; } @@ -537,8 +540,8 @@ static inline int audit_log_drain(struct audit_buffer *ab) if (!audit_pid) { /* No daemon */ int offset = ab->nlh ? NLMSG_SPACE(0) : 0; int len = skb->len - offset; - printk(KERN_ERR "%*.*s\n", - len, len, skb->data + offset); + skb->data[offset + len] = '\0'; + printk(KERN_ERR "%s\n", skb->data + offset); } kfree_skb(skb); ab->nlh = NULL; @@ -617,7 +620,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx) struct audit_buffer *ab = NULL; unsigned long flags; struct timespec t; - int serial = 0; + unsigned int serial; if (!audit_initialized) return NULL; @@ -659,15 +662,16 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx) ab->total = 0; ab->type = AUDIT_KERNEL; ab->pid = 0; - ab->count = 0; #ifdef CONFIG_AUDITSYSCALL if (ab->ctx) audit_get_stamp(ab->ctx, &t, &serial); else #endif + { t = CURRENT_TIME; - + serial = 0; + } audit_log_format(ab, "audit(%lu.%03lu:%u): ", t.tv_sec, t.tv_nsec/1000000, serial); return ab; @@ -717,6 +721,29 @@ void audit_log_format(struct audit_buffer *ab, const char *fmt, ...) va_end(args); } +void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf, size_t len) +{ + int i; + + for (i=0; i<len; i++) + audit_log_format(ab, "%02x", buf[i]); +} + +void audit_log_untrustedstring(struct audit_buffer *ab, const char *string) +{ + const unsigned char *p = string; + + while (*p) { + if (*p == '"' || *p == ' ' || *p < 0x20 || *p > 0x7f) { + audit_log_hex(ab, string, strlen(string)); + return; + } + p++; + } + audit_log_format(ab, "\"%s\"", string); +} + + /* This is a helper-function to print the d_path without using a static * buffer or allocating another buffer in addition to the one in * audit_buffer. */ diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 6f1931381bc..37b3ac94bc4 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1,4 +1,4 @@ -/* auditsc.c -- System-call auditing support -*- linux-c -*- +/* auditsc.c -- System-call auditing support * Handles all system-call specific auditing features. * * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. @@ -123,7 +123,7 @@ struct audit_context { int major; /* syscall number */ unsigned long argv[4]; /* syscall arguments */ int return_valid; /* return code is valid */ - int return_code;/* syscall return code */ + long return_code;/* syscall return code */ int auditable; /* 1 if record should be written */ int name_count; struct audit_names names[AUDIT_NAMES]; @@ -135,6 +135,7 @@ struct audit_context { uid_t uid, euid, suid, fsuid; gid_t gid, egid, sgid, fsgid; unsigned long personality; + int arch; #if AUDIT_DEBUG int put_count; @@ -250,7 +251,8 @@ static int audit_copy_rule(struct audit_rule *d, struct audit_rule *s) return 0; } -int audit_receive_filter(int type, int pid, int uid, int seq, void *data) +int audit_receive_filter(int type, int pid, int uid, int seq, void *data, + uid_t loginuid) { u32 flags; struct audit_entry *entry; @@ -285,6 +287,7 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data) err = audit_add_rule(entry, &audit_entlist); if (!err && (flags & AUDIT_AT_EXIT)) err = audit_add_rule(entry, &audit_extlist); + audit_log(NULL, "auid %u added an audit rule\n", loginuid); break; case AUDIT_DEL: flags =((struct audit_rule *)data)->flags; @@ -294,6 +297,7 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data) err = audit_del_rule(data, &audit_entlist); if (!err && (flags & AUDIT_AT_EXIT)) err = audit_del_rule(data, &audit_extlist); + audit_log(NULL, "auid %u removed an audit rule\n", loginuid); break; default: return -EINVAL; @@ -348,6 +352,10 @@ static int audit_filter_rules(struct task_struct *tsk, case AUDIT_PERS: result = (tsk->personality == value); break; + case AUDIT_ARCH: + if (ctx) + result = (ctx->arch == value); + break; case AUDIT_EXIT: if (ctx && ctx->return_valid) @@ -355,7 +363,7 @@ static int audit_filter_rules(struct task_struct *tsk, break; case AUDIT_SUCCESS: if (ctx && ctx->return_valid) - result = (ctx->return_code >= 0); + result = (ctx->return_valid == AUDITSC_SUCCESS); break; case AUDIT_DEVMAJOR: if (ctx) { @@ -648,8 +656,11 @@ static void audit_log_exit(struct audit_context *context) audit_log_format(ab, "syscall=%d", context->major); if (context->personality != PER_LINUX) audit_log_format(ab, " per=%lx", context->personality); + audit_log_format(ab, " arch=%x", context->arch); if (context->return_valid) - audit_log_format(ab, " exit=%d", context->return_code); + audit_log_format(ab, " success=%s exit=%ld", + (context->return_valid==AUDITSC_SUCCESS)?"yes":"no", + context->return_code); audit_log_format(ab, " a0=%lx a1=%lx a2=%lx a3=%lx items=%d" " pid=%d loginuid=%d uid=%d gid=%d" @@ -696,9 +707,10 @@ static void audit_log_exit(struct audit_context *context) if (!ab) continue; /* audit_panic has been called */ audit_log_format(ab, "item=%d", i); - if (context->names[i].name) - audit_log_format(ab, " name=%s", - context->names[i].name); + if (context->names[i].name) { + audit_log_format(ab, " name="); + audit_log_untrustedstring(ab, context->names[i].name); + } if (context->names[i].ino != (unsigned long)-1) audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#o" " uid=%d gid=%d rdev=%02x:%02x", @@ -772,7 +784,7 @@ static inline unsigned int audit_serial(void) * then the record will be written at syscall exit time (otherwise, it * will only be written if another part of the kernel requests that it * be written). */ -void audit_syscall_entry(struct task_struct *tsk, int major, +void audit_syscall_entry(struct task_struct *tsk, int arch, int major, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4) { @@ -826,6 +838,7 @@ void audit_syscall_entry(struct task_struct *tsk, int major, if (!audit_enabled) return; + context->arch = arch; context->major = major; context->argv[0] = a1; context->argv[1] = a2; @@ -849,13 +862,13 @@ void audit_syscall_entry(struct task_struct *tsk, int major, * filtering, or because some other part of the kernel write an audit * message), then write out the syscall information. In call cases, * free the names stored from getname(). */ -void audit_syscall_exit(struct task_struct *tsk, int return_code) +void audit_syscall_exit(struct task_struct *tsk, int valid, long return_code) { struct audit_context *context; get_task_struct(tsk); task_lock(tsk); - context = audit_get_context(tsk, 1, return_code); + context = audit_get_context(tsk, valid, return_code); task_unlock(tsk); /* Not having a context here is ok, since the parent may have @@ -868,6 +881,7 @@ void audit_syscall_exit(struct task_struct *tsk, int return_code) context->in_syscall = 0; context->auditable = 0; + if (context->previous) { struct audit_context *new_context = context->previous; context->previous = NULL; @@ -981,7 +995,7 @@ void audit_inode(const char *name, const struct inode *inode) } void audit_get_stamp(struct audit_context *ctx, - struct timespec *t, int *serial) + struct timespec *t, unsigned int *serial) { if (ctx) { t->tv_sec = ctx->ctime.tv_sec; @@ -996,20 +1010,21 @@ void audit_get_stamp(struct audit_context *ctx, extern int audit_set_type(struct audit_buffer *ab, int type); -int audit_set_loginuid(struct audit_context *ctx, uid_t loginuid) +int audit_set_loginuid(struct task_struct *task, uid_t loginuid) { - if (ctx) { + if (task->audit_context) { struct audit_buffer *ab; ab = audit_log_start(NULL); if (ab) { audit_log_format(ab, "login pid=%d uid=%u " "old loginuid=%u new loginuid=%u", - ctx->pid, ctx->uid, ctx->loginuid, loginuid); + task->pid, task->uid, + task->audit_context->loginuid, loginuid); audit_set_type(ab, AUDIT_LOGIN); audit_log_end(ab); } - ctx->loginuid = loginuid; + task->audit_context->loginuid = loginuid; } return 0; } diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 4ee39206614..733bf52cef3 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -49,6 +49,8 @@ #include <linux/bitops.h> #include <linux/mm.h> #include <linux/types.h> +#include <linux/audit.h> + #include <net/sock.h> #include <net/scm.h> @@ -904,6 +906,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, NETLINK_CB(skb).groups = nlk->groups; NETLINK_CB(skb).dst_pid = dst_pid; NETLINK_CB(skb).dst_groups = dst_groups; + NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context); memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); /* What can I do? Netlink is asynchronous, so that diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 5a5ddc40f36..09abb891d11 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -2,7 +2,7 @@ # Kernel configuration targets # These targets are used from top-level makefile -.PHONY: oldconfig xconfig gconfig menuconfig config silentoldconfig +.PHONY: oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config xconfig: $(obj)/qconf $< arch/$(ARCH)/Kconfig @@ -23,6 +23,13 @@ oldconfig: $(obj)/conf silentoldconfig: $(obj)/conf $< -s arch/$(ARCH)/Kconfig +update-po-config: $(obj)/kxgettext + xgettext --default-domain=linux \ + --add-comments --keyword=_ --keyword=N_ \ + --files-from=scripts/kconfig/POTFILES.in \ + -o scripts/kconfig/linux.pot + scripts/kconfig/kxgettext arch/$(ARCH)/Kconfig >> scripts/kconfig/linux.pot + .PHONY: randconfig allyesconfig allnoconfig allmodconfig defconfig randconfig: $(obj)/conf @@ -72,9 +79,10 @@ help: # Based on GTK which needs to be installed to compile it # object files used by all kconfig flavours -hostprogs-y := conf mconf qconf gconf +hostprogs-y := conf mconf qconf gconf kxgettext conf-objs := conf.o zconf.tab.o mconf-objs := mconf.o zconf.tab.o +kxgettext-objs := kxgettext.o zconf.tab.o ifeq ($(MAKECMDGOALS),xconfig) qconf-target := 1 @@ -107,7 +115,7 @@ HOSTLOADLIBES_gconf = `pkg-config gtk+-2.0 gmodule-2.0 libglade-2.0 --libs` HOSTCFLAGS_gconf.o = `pkg-config gtk+-2.0 gmodule-2.0 libglade-2.0 --cflags` \ -D LKC_DIRECT_LINK -$(obj)/conf.o $(obj)/mconf.o $(obj)/qconf.o $(obj)/gconf.o: $(obj)/zconf.tab.h +$(obj)/conf.o $(obj)/mconf.o $(obj)/qconf.o $(obj)/gconf.o $(obj)/kxgettext: $(obj)/zconf.tab.h $(obj)/zconf.tab.h: $(src)/zconf.tab.h_shipped $(obj)/zconf.tab.c: $(src)/zconf.tab.c_shipped diff --git a/scripts/kconfig/POTFILES.in b/scripts/kconfig/POTFILES.in new file mode 100644 index 00000000000..cc94e46a79e --- /dev/null +++ b/scripts/kconfig/POTFILES.in @@ -0,0 +1,5 @@ +scripts/kconfig/mconf.c +scripts/kconfig/conf.c +scripts/kconfig/confdata.c +scripts/kconfig/gconf.c +scripts/kconfig/qconf.cc diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index a494d1aeb9f..70e7264c694 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -34,7 +34,7 @@ static int conf_cnt; static signed char line[128]; static struct menu *rootEntry; -static char nohelp_text[] = "Sorry, no help available for this option yet.\n"; +static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n"); static void strip(signed char *str) { @@ -56,9 +56,9 @@ static void strip(signed char *str) static void check_stdin(void) { if (!valid_stdin && input_mode == ask_silent) { - printf("aborted!\n\n"); - printf("Console input/output is redirected. "); - printf("Run 'make oldconfig' to update configuration.\n\n"); + printf(_("aborted!\n\n")); + printf(_("Console input/output is redirected. ")); + printf(_("Run 'make oldconfig' to update configuration.\n\n")); exit(1); } } @@ -470,7 +470,7 @@ static void check_conf(struct menu *menu) if (sym) { if (sym_is_changable(sym) && !sym_has_value(sym)) { if (!conf_cnt++) - printf("*\n* Restart config...\n*\n"); + printf(_("*\n* Restart config...\n*\n")); rootEntry = menu_get_parent_menu(menu); conf(rootEntry); } @@ -504,7 +504,7 @@ int main(int ac, char **av) input_mode = set_default; defconfig_file = av[i++]; if (!defconfig_file) { - printf("%s: No default config file specified\n", + printf(_("%s: No default config file specified\n"), av[0]); exit(1); } @@ -530,7 +530,7 @@ int main(int ac, char **av) } name = av[i]; if (!name) { - printf("%s: Kconfig file missing\n", av[0]); + printf(_("%s: Kconfig file missing\n"), av[0]); } conf_parse(name); //zconfdump(stdout); @@ -547,12 +547,12 @@ int main(int ac, char **av) break; case ask_silent: if (stat(".config", &tmpstat)) { - printf("***\n" + printf(_("***\n" "*** You have not yet configured your kernel!\n" "***\n" "*** Please run some configurator (e.g. \"make oldconfig\" or\n" "*** \"make menuconfig\" or \"make xconfig\").\n" - "***\n"); + "***\n")); exit(1); } case ask_all: @@ -576,7 +576,7 @@ int main(int ac, char **av) check_conf(&rootmenu); } while (conf_cnt); if (conf_write(NULL)) { - fprintf(stderr, "\n*** Error during writing of the kernel configuration.\n\n"); + fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n")); return 1; } return 0; diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 1e82ae390a6..2755c459d78 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -88,9 +88,9 @@ int conf_read(const char *name) name = conf_expand_value(name); in = zconf_fopen(name); if (in) { - printf("#\n" - "# using defaults found in %s\n" - "#\n", name); + printf(_("#\n" + "# using defaults found in %s\n" + "#\n"), name); break; } } @@ -312,11 +312,11 @@ int conf_write(const char *name) if (env && *env) use_timestamp = 0; - fprintf(out, "#\n" - "# Automatically generated make config: don't edit\n" - "# Linux kernel version: %s\n" - "%s%s" - "#\n", + fprintf(out, _("#\n" + "# Automatically generated make config: don't edit\n" + "# Linux kernel version: %s\n" + "%s%s" + "#\n"), sym_get_string_value(sym), use_timestamp ? "# " : "", use_timestamp ? ctime(&now) : ""); diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c index 6fdbe6e3ce0..ad6b1204387 100644 --- a/scripts/kconfig/gconf.c +++ b/scripts/kconfig/gconf.c @@ -41,7 +41,7 @@ static gboolean resizeable = FALSE; static gboolean config_changed = FALSE; static char nohelp_text[] = - "Sorry, no help available for this option yet.\n"; + N_("Sorry, no help available for this option yet.\n"); GtkWidget *main_wnd = NULL; GtkWidget *tree1_w = NULL; // left frame @@ -193,7 +193,7 @@ void init_main_window(const gchar * glade_file) xml = glade_xml_new(glade_file, "window1", NULL); if (!xml) - g_error("GUI loading failed !\n"); + g_error(_("GUI loading failed !\n")); glade_xml_signal_autoconnect(xml); main_wnd = glade_xml_get_widget(xml, "window1"); @@ -275,7 +275,7 @@ void init_main_window(const gchar * glade_file) /*"style", PANGO_STYLE_OBLIQUE, */ NULL); - sprintf(title, "Linux Kernel v%s Configuration", + sprintf(title, _("Linux Kernel v%s Configuration"), getenv("KERNELRELEASE")); gtk_window_set_title(GTK_WINDOW(main_wnd), title); @@ -325,7 +325,7 @@ void init_left_tree(void) column = gtk_tree_view_column_new(); gtk_tree_view_append_column(view, column); - gtk_tree_view_column_set_title(column, "Options"); + gtk_tree_view_column_set_title(column, _("Options")); renderer = gtk_cell_renderer_toggle_new(); gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), @@ -370,7 +370,7 @@ void init_right_tree(void) column = gtk_tree_view_column_new(); gtk_tree_view_append_column(view, column); - gtk_tree_view_column_set_title(column, "Options"); + gtk_tree_view_column_set_title(column, _("Options")); renderer = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), @@ -401,7 +401,7 @@ void init_right_tree(void) renderer = gtk_cell_renderer_text_new(); gtk_tree_view_insert_column_with_attributes(view, -1, - "Name", renderer, + _("Name"), renderer, "text", COL_NAME, "foreground-gdk", COL_COLOR, NULL); @@ -425,7 +425,7 @@ void init_right_tree(void) COL_COLOR, NULL); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_insert_column_with_attributes(view, -1, - "Value", renderer, + _("Value"), renderer, "text", COL_VALUE, "editable", COL_EDIT, @@ -466,15 +466,15 @@ static void text_insert_help(struct menu *menu) GtkTextIter start, end; const char *prompt = menu_get_prompt(menu); gchar *name; - const char *help = nohelp_text; + const char *help = _(nohelp_text); if (!menu->sym) help = ""; else if (menu->sym->help) - help = menu->sym->help; + help = _(menu->sym->help); if (menu->sym && menu->sym->name) - name = g_strdup_printf(menu->sym->name); + name = g_strdup_printf(_(menu->sym->name)); else name = g_strdup(""); @@ -530,7 +530,7 @@ gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event, if (config_changed == FALSE) return FALSE; - dialog = gtk_dialog_new_with_buttons("Warning !", + dialog = gtk_dialog_new_with_buttons(_("Warning !"), GTK_WINDOW(main_wnd), (GtkDialogFlags) (GTK_DIALOG_MODAL | @@ -544,7 +544,7 @@ gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event, gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL); - label = gtk_label_new("\nSave configuration ?\n"); + label = gtk_label_new(_("\nSave configuration ?\n")); gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); gtk_widget_show(label); @@ -604,7 +604,7 @@ load_filename(GtkFileSelection * file_selector, gpointer user_data) (user_data)); if (conf_read(fn)) - text_insert_msg("Error", "Unable to load configuration !"); + text_insert_msg(_("Error"), _("Unable to load configuration !")); else display_tree(&rootmenu); } @@ -613,7 +613,7 @@ void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkWidget *fs; - fs = gtk_file_selection_new("Load file..."); + fs = gtk_file_selection_new(_("Load file...")); g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), "clicked", G_CALLBACK(load_filename), (gpointer) fs); @@ -632,7 +632,7 @@ void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data) void on_save1_activate(GtkMenuItem * menuitem, gpointer user_data) { if (conf_write(NULL)) - text_insert_msg("Error", "Unable to save configuration !"); + text_insert_msg(_("Error"), _("Unable to save configuration !")); config_changed = FALSE; } @@ -647,7 +647,7 @@ store_filename(GtkFileSelection * file_selector, gpointer user_data) (user_data)); if (conf_write(fn)) - text_insert_msg("Error", "Unable to save configuration !"); + text_insert_msg(_("Error"), _("Unable to save configuration !")); gtk_widget_destroy(GTK_WIDGET(user_data)); } @@ -656,7 +656,7 @@ void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkWidget *fs; - fs = gtk_file_selection_new("Save file as..."); + fs = gtk_file_selection_new(_("Save file as...")); g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), "clicked", G_CALLBACK(store_filename), (gpointer) fs); @@ -740,7 +740,7 @@ on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data) void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkWidget *dialog; - const gchar *intro_text = + const gchar *intro_text = _( "Welcome to gkc, the GTK+ graphical kernel configuration tool\n" "for Linux.\n" "For each option, a blank box indicates the feature is disabled, a\n" @@ -756,7 +756,7 @@ void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data) "option.\n" "\n" "Toggling Show Debug Info under the Options menu will show \n" - "the dependencies, which you can then match by examining other options."; + "the dependencies, which you can then match by examining other options."); dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), GTK_DIALOG_DESTROY_WITH_PARENT, @@ -773,8 +773,8 @@ void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkWidget *dialog; const gchar *about_text = - "gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n" - "Based on the source code from Roman Zippel.\n"; + _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n" + "Based on the source code from Roman Zippel.\n"); dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), GTK_DIALOG_DESTROY_WITH_PARENT, @@ -791,9 +791,9 @@ void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkWidget *dialog; const gchar *license_text = - "gkc is released under the terms of the GNU GPL v2.\n" - "For more information, please see the source code or\n" - "visit http://www.fsf.org/licenses/licenses.html\n"; + _("gkc is released under the terms of the GNU GPL v2.\n" + "For more information, please see the source code or\n" + "visit http://www.fsf.org/licenses/licenses.html\n"); dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), GTK_DIALOG_DESTROY_WITH_PARENT, @@ -1579,6 +1579,10 @@ int main(int ac, char *av[]) kconfig_load(); #endif + bindtextdomain(PACKAGE, LOCALEDIR); + bind_textdomain_codeset(PACKAGE, "UTF-8"); + textdomain(PACKAGE); + /* GTK stuffs */ gtk_set_locale(); gtk_init(&ac, &av); diff --git a/scripts/kconfig/kxgettext.c b/scripts/kconfig/kxgettext.c new file mode 100644 index 00000000000..1c88d7c6d5a --- /dev/null +++ b/scripts/kconfig/kxgettext.c @@ -0,0 +1,221 @@ +/* + * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2005 + * + * Released under the terms of the GNU GPL v2.0 + */ + +#include <stdlib.h> +#include <string.h> + +#define LKC_DIRECT_LINK +#include "lkc.h" + +static char *escape(const char* text, char *bf, int len) +{ + char *bfp = bf; + int multiline = strchr(text, '\n') != NULL; + + *bfp++ = '"'; + --len; + + if (multiline) { + *bfp++ = '"'; + *bfp++ = '\n'; + *bfp++ = '"'; + len -= 3; + } + + while (*text != '\0' && len > 1) { + if (*text == '"') + *bfp++ = '\\'; + else if (*text == '\n') { + *bfp++ = '\\'; + *bfp++ = 'n'; + *bfp++ = '"'; + *bfp++ = '\n'; + *bfp++ = '"'; + len -= 5; + ++text; + goto next; + } + *bfp++ = *text++; +next: + --len; + } + + if (multiline) + bfp -= 3; + + *bfp++ = '"'; + *bfp = '\0'; + + return bf; +} + +struct file_line { + struct file_line *next; + char* file; + int lineno; +}; + +static struct file_line *file_line__new(char *file, int lineno) +{ + struct file_line *self = malloc(sizeof(*self)); + + if (self == NULL) + goto out; + + self->file = file; + self->lineno = lineno; + self->next = NULL; +out: + return self; +} + +struct message { + const char *msg; + const char *option; + struct message *next; + struct file_line *files; +}; + +static struct message *message__list; + +static struct message *message__new(const char *msg, char *option, char *file, int lineno) +{ + struct message *self = malloc(sizeof(*self)); + + if (self == NULL) + goto out; + + self->files = file_line__new(file, lineno); + if (self->files == NULL) + goto out_fail; + + self->msg = strdup(msg); + if (self->msg == NULL) + goto out_fail_msg; + + self->option = option; + self->next = NULL; +out: + return self; +out_fail_msg: + free(self->files); +out_fail: + free(self); + self = NULL; + goto out; +} + +static struct message *mesage__find(const char *msg) +{ + struct message *m = message__list; + + while (m != NULL) { + if (strcmp(m->msg, msg) == 0) + break; + m = m->next; + } + + return m; +} + +static int message__add_file_line(struct message *self, char *file, int lineno) +{ + int rc = -1; + struct file_line *fl = file_line__new(file, lineno); + + if (fl == NULL) + goto out; + + fl->next = self->files; + self->files = fl; + rc = 0; +out: + return rc; +} + +static int message__add(const char *msg, char *option, char *file, int lineno) +{ + int rc = 0; + char bf[16384]; + char *escaped = escape(msg, bf, sizeof(bf)); + struct message *m = mesage__find(escaped); + + if (m != NULL) + rc = message__add_file_line(m, file, lineno); + else { + m = message__new(escaped, option, file, lineno); + + if (m != NULL) { + m->next = message__list; + message__list = m; + } else + rc = -1; + } + return rc; +} + +void menu_build_message_list(struct menu *menu) +{ + struct menu *child; + + message__add(menu_get_prompt(menu), NULL, + menu->file == NULL ? "Root Menu" : menu->file->name, + menu->lineno); + + if (menu->sym != NULL && menu->sym->help != NULL) + message__add(menu->sym->help, menu->sym->name, + menu->file == NULL ? "Root Menu" : menu->file->name, + menu->lineno); + + for (child = menu->list; child != NULL; child = child->next) + if (child->prompt != NULL) + menu_build_message_list(child); +} + +static void message__print_file_lineno(struct message *self) +{ + struct file_line *fl = self->files; + + printf("\n#: %s:%d", fl->file, fl->lineno); + fl = fl->next; + + while (fl != NULL) { + printf(", %s:%d", fl->file, fl->lineno); + fl = fl->next; + } + + if (self->option != NULL) + printf(", %s:00000", self->option); + + putchar('\n'); +} + +static void message__print_gettext_msgid_msgstr(struct message *self) +{ + message__print_file_lineno(self); + + printf("msgid %s\n" + "msgstr \"\"\n", self->msg); +} + +void menu__xgettext(void) +{ + struct message *m = message__list; + + while (m != NULL) { + message__print_gettext_msgid_msgstr(m); + m = m->next; + } +} + +int main(int ac, char **av) +{ + conf_parse(av[1]); + + menu_build_message_list(menu_get_root_menu(NULL)); + menu__xgettext(); + return 0; +} diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index b8a67fc9d64..8b84c42b49b 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -8,6 +8,8 @@ #include "expr.h" +#include <libintl.h> + #ifdef __cplusplus extern "C" { #endif @@ -23,6 +25,12 @@ extern "C" { #define SRCTREE "srctree" +#define PACKAGE "linux" +#define LOCALEDIR "/usr/share/locale" + +#define _(text) gettext(text) +#define N_(text) (text) + int zconfparse(void); void zconfdump(FILE *out); diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 730d316fe7f..e5db10ca956 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -4,6 +4,8 @@ * * Introduced single menu mode (show all sub-menus in one large tree). * 2002-11-06 Petr Baudis <pasky@ucw.cz> + * + * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br> */ #include <sys/ioctl.h> @@ -23,7 +25,7 @@ #include "lkc.h" static char menu_backtitle[128]; -static const char mconf_readme[] = +static const char mconf_readme[] = N_( "Overview\n" "--------\n" "Some kernel features may be built directly into the kernel.\n" @@ -156,39 +158,39 @@ static const char mconf_readme[] = "\n" "Note that this mode can eventually be a little more CPU expensive\n" "(especially with a larger number of unrolled categories) than the\n" -"default mode.\n", -menu_instructions[] = +"default mode.\n"), +menu_instructions[] = N_( "Arrow keys navigate the menu. " "<Enter> selects submenus --->. " "Highlighted letters are hotkeys. " "Pressing <Y> includes, <N> excludes, <M> modularizes features. " "Press <Esc><Esc> to exit, <?> for Help, </> for Search. " - "Legend: [*] built-in [ ] excluded <M> module < > module capable", -radiolist_instructions[] = + "Legend: [*] built-in [ ] excluded <M> module < > module capable"), +radiolist_instructions[] = N_( "Use the arrow keys to navigate this window or " "press the hotkey of the item you wish to select " "followed by the <SPACE BAR>. " - "Press <?> for additional information about this option.", -inputbox_instructions_int[] = + "Press <?> for additional information about this option."), +inputbox_instructions_int[] = N_( "Please enter a decimal value. " "Fractions will not be accepted. " - "Use the <TAB> key to move from the input field to the buttons below it.", -inputbox_instructions_hex[] = + "Use the <TAB> key to move from the input field to the buttons below it."), +inputbox_instructions_hex[] = N_( "Please enter a hexadecimal value. " - "Use the <TAB> key to move from the input field to the buttons below it.", -inputbox_instructions_string[] = + "Use the <TAB> key to move from the input field to the buttons below it."), +inputbox_instructions_string[] = N_( "Please enter a string value. " - "Use the <TAB> key to move from the input field to the buttons below it.", -setmod_text[] = + "Use the <TAB> key to move from the input field to the buttons below it."), +setmod_text[] = N_( "This feature depends on another which has been configured as a module.\n" - "As a result, this feature will be built as a module.", -nohelp_text[] = - "There is no help available for this kernel option.\n", -load_config_text[] = + "As a result, this feature will be built as a module."), +nohelp_text[] = N_( + "There is no help available for this kernel option.\n"), +load_config_text[] = N_( "Enter the name of the configuration file you wish to load. " "Accept the name shown to restore the configuration you " - "last retrieved. Leave blank to abort.", -load_config_help[] = + "last retrieved. Leave blank to abort."), +load_config_help[] = N_( "\n" "For various reasons, one may wish to keep several different kernel\n" "configurations available on a single machine.\n" @@ -198,11 +200,11 @@ load_config_help[] = "to modify that configuration.\n" "\n" "If you are uncertain, then you have probably never used alternate\n" - "configuration files. You should therefor leave this blank to abort.\n", -save_config_text[] = + "configuration files. You should therefor leave this blank to abort.\n"), +save_config_text[] = N_( "Enter a filename to which this configuration should be saved " - "as an alternate. Leave blank to abort.", -save_config_help[] = + "as an alternate. Leave blank to abort."), +save_config_help[] = N_( "\n" "For various reasons, one may wish to keep different kernel\n" "configurations available on a single machine.\n" @@ -212,8 +214,8 @@ save_config_help[] = "configuration options you have selected at that time.\n" "\n" "If you are uncertain what all this means then you should probably\n" - "leave this blank.\n", -search_help[] = + "leave this blank.\n"), +search_help[] = N_( "\n" "Search for CONFIG_ symbols and display their relations.\n" "Example: search for \"^FOO\"\n" @@ -250,7 +252,7 @@ search_help[] = "Examples: USB => find all CONFIG_ symbols containing USB\n" " ^USB => find all CONFIG_ symbols starting with USB\n" " USB$ => find all CONFIG_ symbols ending with USB\n" - "\n"; + "\n"); static signed char buf[4096], *bufptr = buf; static signed char input_buf[4096]; @@ -305,8 +307,8 @@ static void init_wsize(void) } if (rows < 19 || cols < 80) { - fprintf(stderr, "Your display is too small to run Menuconfig!\n"); - fprintf(stderr, "It must be at least 19 lines by 80 columns.\n"); + fprintf(stderr, N_("Your display is too small to run Menuconfig!\n")); + fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n")); exit(1); } @@ -526,9 +528,9 @@ static void search_conf(void) again: cprint_init(); cprint("--title"); - cprint("Search Configuration Parameter"); + cprint(_("Search Configuration Parameter")); cprint("--inputbox"); - cprint("Enter Keyword"); + cprint(_("Enter Keyword")); cprint("10"); cprint("75"); cprint(""); @@ -539,7 +541,7 @@ again: case 0: break; case 1: - show_helptext("Search Configuration", search_help); + show_helptext(_("Search Configuration"), search_help); goto again; default: return; @@ -548,7 +550,7 @@ again: sym_arr = sym_re_search(input_buf); res = get_relations_str(sym_arr); free(sym_arr); - show_textbox("Search Results", str_get(&res), 0, 0); + show_textbox(_("Search Results"), str_get(&res), 0, 0); str_free(&res); } @@ -721,9 +723,9 @@ static void conf(struct menu *menu) while (1) { cprint_init(); cprint("--title"); - cprint("%s", prompt ? prompt : "Main Menu"); + cprint("%s", prompt ? prompt : _("Main Menu")); cprint("--menu"); - cprint(menu_instructions); + cprint(_(menu_instructions)); cprint("%d", rows); cprint("%d", cols); cprint("%d", rows - 10); @@ -736,9 +738,9 @@ static void conf(struct menu *menu) cprint(":"); cprint("--- "); cprint("L"); - cprint(" Load an Alternate Configuration File"); + cprint(_(" Load an Alternate Configuration File")); cprint("S"); - cprint(" Save Configuration to an Alternate File"); + cprint(_(" Save Configuration to an Alternate File")); } stat = exec_conf(); if (stat < 0) @@ -793,7 +795,7 @@ static void conf(struct menu *menu) if (sym) show_help(submenu); else - show_helptext("README", mconf_readme); + show_helptext("README", _(mconf_readme)); break; case 3: if (type == 't') { @@ -849,7 +851,7 @@ static void show_help(struct menu *menu) { if (sym->name) { str_printf(&help, "CONFIG_%s:\n\n", sym->name); - str_append(&help, sym->help); + str_append(&help, _(sym->help)); str_append(&help, "\n"); } } else { @@ -886,9 +888,9 @@ static void conf_choice(struct menu *menu) while (1) { cprint_init(); cprint("--title"); - cprint("%s", prompt ? prompt : "Main Menu"); + cprint("%s", prompt ? prompt : _("Main Menu")); cprint("--radiolist"); - cprint(radiolist_instructions); + cprint(_(radiolist_instructions)); cprint("15"); cprint("70"); cprint("6"); @@ -935,17 +937,17 @@ static void conf_string(struct menu *menu) while (1) { cprint_init(); cprint("--title"); - cprint("%s", prompt ? prompt : "Main Menu"); + cprint("%s", prompt ? prompt : _("Main Menu")); cprint("--inputbox"); switch (sym_get_type(menu->sym)) { case S_INT: - cprint(inputbox_instructions_int); + cprint(_(inputbox_instructions_int)); break; case S_HEX: - cprint(inputbox_instructions_hex); + cprint(_(inputbox_instructions_hex)); break; case S_STRING: - cprint(inputbox_instructions_string); + cprint(_(inputbox_instructions_string)); break; default: /* panic? */; @@ -958,7 +960,7 @@ static void conf_string(struct menu *menu) case 0: if (sym_set_string_value(menu->sym, input_buf)) return; - show_textbox(NULL, "You have made an invalid entry.", 5, 43); + show_textbox(NULL, _("You have made an invalid entry."), 5, 43); break; case 1: show_help(menu); @@ -987,10 +989,10 @@ static void conf_load(void) return; if (!conf_read(input_buf)) return; - show_textbox(NULL, "File does not exist!", 5, 38); + show_textbox(NULL, _("File does not exist!"), 5, 38); break; case 1: - show_helptext("Load Alternate Configuration", load_config_help); + show_helptext(_("Load Alternate Configuration"), load_config_help); break; case 255: return; @@ -1016,10 +1018,10 @@ static void conf_save(void) return; if (!conf_write(input_buf)) return; - show_textbox(NULL, "Can't create file! Probably a nonexistent directory.", 5, 60); + show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60); break; case 1: - show_helptext("Save Alternate Configuration", save_config_help); + show_helptext(_("Save Alternate Configuration"), save_config_help); break; case 255: return; @@ -1040,12 +1042,16 @@ int main(int ac, char **av) char *mode; int stat; + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + conf_parse(av[1]); conf_read(NULL); sym = sym_lookup("KERNELRELEASE", 0); sym_calc_value(sym); - sprintf(menu_backtitle, "Linux Kernel v%s Configuration", + sprintf(menu_backtitle, _("Linux Kernel v%s Configuration"), sym_get_string_value(sym)); mode = getenv("MENUCONFIG_MODE"); @@ -1062,7 +1068,7 @@ int main(int ac, char **av) do { cprint_init(); cprint("--yesno"); - cprint("Do you wish to save your new kernel configuration?"); + cprint(_("Do you wish to save your new kernel configuration?")); cprint("5"); cprint("60"); stat = exec_conf(); @@ -1070,20 +1076,20 @@ int main(int ac, char **av) if (stat == 0) { if (conf_write(NULL)) { - fprintf(stderr, "\n\n" + fprintf(stderr, _("\n\n" "Error during writing of the kernel configuration.\n" "Your kernel configuration changes were NOT saved." - "\n\n"); + "\n\n")); return 1; } - printf("\n\n" + printf(_("\n\n" "*** End of Linux kernel configuration.\n" "*** Execute 'make' to build the kernel or try 'make help'." - "\n\n"); + "\n\n")); } else { - fprintf(stderr, "\n\n" + fprintf(stderr, _("\n\n" "Your kernel configuration changes were NOT saved." - "\n\n"); + "\n\n")); } return 0; diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 0c13156f334..8c59b212722 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -365,9 +365,9 @@ bool menu_is_visible(struct menu *menu) const char *menu_get_prompt(struct menu *menu) { if (menu->prompt) - return menu->prompt->text; + return _(menu->prompt->text); else if (menu->sym) - return menu->sym->name; + return _(menu->sym->name); return NULL; } diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 0cdbf9dbbd5..4590cd31623 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -26,8 +26,23 @@ #include "qconf.moc" #include "images.c" +#ifdef _ +# undef _ +# define _ qgettext +#endif + static QApplication *configApp; +static inline QString qgettext(const char* str) +{ + return QString::fromLocal8Bit(gettext(str)); +} + +static inline QString qgettext(const QString& str) +{ + return QString::fromLocal8Bit(gettext(str.latin1())); +} + ConfigSettings::ConfigSettings() : showAll(false), showName(false), showRange(false), showData(false) { @@ -177,7 +192,7 @@ void ConfigItem::updateMenu(void) sym = menu->sym; prop = menu->prompt; - prompt = menu_get_prompt(menu); + prompt = QString::fromLocal8Bit(menu_get_prompt(menu)); if (prop) switch (prop->type) { case P_MENU: @@ -203,7 +218,7 @@ void ConfigItem::updateMenu(void) if (!sym) goto set_prompt; - setText(nameColIdx, sym->name); + setText(nameColIdx, QString::fromLocal8Bit(sym->name)); type = sym_get_type(sym); switch (type) { @@ -213,9 +228,9 @@ void ConfigItem::updateMenu(void) if (!sym_is_changable(sym) && !list->showAll) { setPixmap(promptColIdx, 0); - setText(noColIdx, 0); - setText(modColIdx, 0); - setText(yesColIdx, 0); + setText(noColIdx, QString::null); + setText(modColIdx, QString::null); + setText(yesColIdx, QString::null); break; } expr = sym_get_tristate_value(sym); @@ -257,6 +272,7 @@ void ConfigItem::updateMenu(void) const char* data; data = sym_get_string_value(sym); + #if QT_VERSION >= 300 int i = list->mapIdx(dataColIdx); if (i >= 0) @@ -264,9 +280,9 @@ void ConfigItem::updateMenu(void) #endif setText(dataColIdx, data); if (type == S_STRING) - prompt.sprintf("%s: %s", prompt.latin1(), data); + prompt = QString("%1: %2").arg(prompt).arg(data); else - prompt.sprintf("(%s) %s", data, prompt.latin1()); + prompt = QString("(%2) %1").arg(prompt).arg(data); break; } if (!sym_has_value(sym) && visible) @@ -343,9 +359,9 @@ void ConfigLineEdit::show(ConfigItem* i) { item = i; if (sym_get_string_value(item->menu->sym)) - setText(sym_get_string_value(item->menu->sym)); + setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym))); else - setText(0); + setText(QString::null); Parent::show(); setFocus(); } @@ -961,7 +977,7 @@ ConfigMainWindow::ConfigMainWindow(void) delete configSettings; } -static QString print_filter(const char *str) +static QString print_filter(const QString &str) { QRegExp re("[<>&\"\\n]"); QString res = str; @@ -994,7 +1010,7 @@ static QString print_filter(const char *str) static void expr_print_help(void *data, const char *str) { - ((QString*)data)->append(print_filter(str)); + reinterpret_cast<QString*>(data)->append(print_filter(str)); } /* @@ -1009,7 +1025,7 @@ void ConfigMainWindow::setHelp(QListViewItem* item) if (item) menu = ((ConfigItem*)item)->menu; if (!menu) { - helpText->setText(NULL); + helpText->setText(QString::null); return; } @@ -1019,16 +1035,16 @@ void ConfigMainWindow::setHelp(QListViewItem* item) if (sym) { if (menu->prompt) { head += "<big><b>"; - head += print_filter(menu->prompt->text); + head += print_filter(_(menu->prompt->text)); head += "</b></big>"; if (sym->name) { head += " ("; - head += print_filter(sym->name); + head += print_filter(_(sym->name)); head += ")"; } } else if (sym->name) { head += "<big><b>"; - head += print_filter(sym->name); + head += print_filter(_(sym->name)); head += "</b></big>"; } head += "<br><br>"; @@ -1049,7 +1065,7 @@ void ConfigMainWindow::setHelp(QListViewItem* item) case P_PROMPT: case P_MENU: debug += "prompt: "; - debug += print_filter(prop->text); + debug += print_filter(_(prop->text)); debug += "<br>"; break; case P_DEFAULT: @@ -1088,10 +1104,10 @@ void ConfigMainWindow::setHelp(QListViewItem* item) debug += "<br>"; } - help = print_filter(sym->help); + help = print_filter(_(sym->help)); } else if (menu->prompt) { head += "<big><b>"; - head += print_filter(menu->prompt->text); + head += print_filter(_(menu->prompt->text)); head += "</b></big><br><br>"; if (showDebug) { if (menu->prompt->visible.expr) { @@ -1111,7 +1127,7 @@ void ConfigMainWindow::loadConfig(void) QString s = QFileDialog::getOpenFileName(".config", NULL, this); if (s.isNull()) return; - if (conf_read(s.latin1())) + if (conf_read(QFile::encodeName(s))) QMessageBox::information(this, "qconf", "Unable to load configuration!"); ConfigView::updateListAll(); } @@ -1127,7 +1143,7 @@ void ConfigMainWindow::saveConfigAs(void) QString s = QFileDialog::getSaveFileName(".config", NULL, this); if (s.isNull()) return; - if (conf_write(s.latin1())) + if (conf_write(QFile::encodeName(s))) QMessageBox::information(this, "qconf", "Unable to save configuration!"); } @@ -1372,6 +1388,9 @@ int main(int ac, char** av) ConfigMainWindow* v; const char *name; + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + #ifndef LKC_DIRECT_LINK kconfig_load(); #endif |