From 4cc329ec856b828bb5dc306d9d0574619b8815a0 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 10 Jan 2005 12:58:17 -0500 Subject: [PATCH] mark arcdev_setup static It's only used in arcnet.c, and following the model of the other link layers it doesn't make sense to use it outside alloc_arcdev() either. --- include/linux/arcdevice.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h index bd4364daf948..7198f129e135 100644 --- a/include/linux/arcdevice.h +++ b/include/linux/arcdevice.h @@ -343,7 +343,6 @@ void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc, void arcnet_unregister_proto(struct ArcProto *proto); irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs); -void arcdev_setup(struct net_device *dev); struct net_device *alloc_arcdev(char *name); void arcnet_rx(struct net_device *dev, int bufnum); -- cgit v1.2.3 From 357bdf2ac6f6f2c57bce76d819b4605e92897a58 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 10 Jan 2005 16:57:45 -0800 Subject: [PATCH] quota: make some code static The patch below makes some needlessly global code static. The most interesting part is that dquot_cachep can become static, since it isn't used outside of dquot.c . Signed-off-by: Adrian Bunk Acked-by: Jan Kara Signed-off-by: Linus Torvalds --- fs/dquot.c | 8 ++++---- fs/quota.c | 2 +- include/linux/slab.h | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/fs/dquot.c b/fs/dquot.c index ce53e60bd227..8455855e751a 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -128,6 +128,9 @@ static char *quotatypes[] = INITQFNAMES; static struct quota_format_type *quota_formats; /* List of registered formats */ static struct quota_module_name module_names[] = INIT_QUOTA_MODULE_NAMES; +/* SLAB cache for dquot structures */ +static kmem_cache_t *dquot_cachep; + int register_quota_format(struct quota_format_type *fmt) { spin_lock(&dq_list_lock); @@ -199,7 +202,7 @@ static void put_quota_format(struct quota_format_type *fmt) static LIST_HEAD(inuse_list); static LIST_HEAD(free_dquots); -unsigned int dq_hash_bits, dq_hash_mask; +static unsigned int dq_hash_bits, dq_hash_mask; static struct hlist_head *dquot_hash; struct dqstats dqstats; @@ -1781,9 +1784,6 @@ static ctl_table sys_table[] = { { .ctl_name = 0 }, }; -/* SLAB cache for dquot structures */ -kmem_cache_t *dquot_cachep; - static int __init dquot_init(void) { int i; diff --git a/fs/quota.c b/fs/quota.c index e69e8d1ada84..d59ccf2358b5 100644 --- a/fs/quota.c +++ b/fs/quota.c @@ -136,7 +136,7 @@ restart: return NULL; } -void quota_sync_sb(struct super_block *sb, int type) +static void quota_sync_sb(struct super_block *sb, int type) { int cnt; struct inode *discard[MAXQUOTAS]; diff --git a/include/linux/slab.h b/include/linux/slab.h index 93c8264fe67b..0c7ae4f678a2 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -118,7 +118,6 @@ extern kmem_cache_t *mm_cachep; extern kmem_cache_t *names_cachep; extern kmem_cache_t *files_cachep; extern kmem_cache_t *filp_cachep; -extern kmem_cache_t *dquot_cachep; extern kmem_cache_t *fs_cachep; extern kmem_cache_t *signal_cachep; extern kmem_cache_t *sighand_cachep; -- cgit v1.2.3 From 7f01bafbc7463ed7b02bf1c0187cac1c01c922c8 Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Mon, 10 Jan 2005 17:10:38 -0800 Subject: [PATCH] split bprm_apply_creds into two functions The following patch splits bprm_apply_creds into two functions, bprm_apply_creds and bprm_post_apply_creds. The latter is called after the task_lock has been dropped. Without this patch, SELinux must drop the task_lock and re-acquire it during apply_creds, making the 'unsafe' flag meaningless to any later security modules. Please apply. Signed-off-by: Serge Hallyn Signed-off-by: Stephen Smalley Signed-off-by: Chris Wright Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/exec.c | 1 + include/linux/security.h | 25 +++++-- security/dummy.c | 6 ++ security/selinux/hooks.c | 148 ++++++++++++++++++++------------------ security/selinux/include/objsec.h | 6 ++ 5 files changed, 112 insertions(+), 74 deletions(-) (limited to 'include/linux') diff --git a/fs/exec.c b/fs/exec.c index c401dc74226e..ffe22877ca94 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -963,6 +963,7 @@ void compute_creds(struct linux_binprm *bprm) unsafe = unsafe_exec(current); security_bprm_apply_creds(bprm, unsafe); task_unlock(current); + security_bprm_post_apply_creds(bprm); } EXPORT_SYMBOL(compute_creds); diff --git a/include/linux/security.h b/include/linux/security.h index 4e0795b5a276..2b048ec62e9c 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -109,13 +109,20 @@ struct swap_info_struct; * and the information saved in @bprm->security by the set_security hook. * Since this hook function (and its caller) are void, this hook can not * return an error. However, it can leave the security attributes of the - * process unchanged if an access failure occurs at this point. It can - * also perform other state changes on the process (e.g. closing open - * file descriptors to which access is no longer granted if the attributes - * were changed). + * process unchanged if an access failure occurs at this point. * bprm_apply_creds is called under task_lock. @unsafe indicates various * reasons why it may be unsafe to change security state. * @bprm contains the linux_binprm structure. + * @bprm_post_apply_creds: + * Runs after bprm_apply_creds with the task_lock dropped, so that + * functions which cannot be called safely under the task_lock can + * be used. This hook is a good place to perform state changes on + * the process such as closing open file descriptors to which access + * is no longer granted if the attributes were changed. + * Note that a security module might need to save state between + * bprm_apply_creds and bprm_post_apply_creds to store the decision + * on whether the process may proceed. + * @bprm contains the linux_binprm structure. * @bprm_set_security: * Save security information in the bprm->security field, typically based * on information about the bprm->file, for later use by the apply_creds @@ -1042,6 +1049,7 @@ struct security_operations { int (*bprm_alloc_security) (struct linux_binprm * bprm); void (*bprm_free_security) (struct linux_binprm * bprm); void (*bprm_apply_creds) (struct linux_binprm * bprm, int unsafe); + void (*bprm_post_apply_creds) (struct linux_binprm * bprm); int (*bprm_set_security) (struct linux_binprm * bprm); int (*bprm_check_security) (struct linux_binprm * bprm); int (*bprm_secureexec) (struct linux_binprm * bprm); @@ -1314,6 +1322,10 @@ static inline void security_bprm_apply_creds (struct linux_binprm *bprm, int uns { security_ops->bprm_apply_creds (bprm, unsafe); } +static inline void security_bprm_post_apply_creds (struct linux_binprm *bprm) +{ + security_ops->bprm_post_apply_creds (bprm); +} static inline int security_bprm_set (struct linux_binprm *bprm) { return security_ops->bprm_set_security (bprm); @@ -1992,6 +2004,11 @@ static inline void security_bprm_apply_creds (struct linux_binprm *bprm, int uns cap_bprm_apply_creds (bprm, unsafe); } +static inline void security_bprm_post_apply_creds (struct linux_binprm *bprm) +{ + return; +} + static inline int security_bprm_set (struct linux_binprm *bprm) { return cap_bprm_set_security (bprm); diff --git a/security/dummy.c b/security/dummy.c index ce3deb72a87f..16d48b15ca1b 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -200,6 +200,11 @@ static void dummy_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) dummy_capget(current, ¤t->cap_effective, ¤t->cap_inheritable, ¤t->cap_permitted); } +static void dummy_bprm_post_apply_creds (struct linux_binprm *bprm) +{ + return; +} + static int dummy_bprm_set_security (struct linux_binprm *bprm) { return 0; @@ -916,6 +921,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, bprm_alloc_security); set_to_dummy_if_null(ops, bprm_free_security); set_to_dummy_if_null(ops, bprm_apply_creds); + set_to_dummy_if_null(ops, bprm_post_apply_creds); set_to_dummy_if_null(ops, bprm_set_security); set_to_dummy_if_null(ops, bprm_check_security); set_to_dummy_if_null(ops, bprm_secureexec); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a480aa47a9d3..2cbabb33c2a9 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1795,10 +1795,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) struct task_security_struct *tsec; struct bprm_security_struct *bsec; u32 sid; - struct av_decision avd; - struct itimerval itimer; - struct rlimit *rlim, *initrlim; - int rc, i; + int rc; secondary_ops->bprm_apply_creds(bprm, unsafe); @@ -1808,91 +1805,101 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) sid = bsec->sid; tsec->osid = tsec->sid; + bsec->unsafe = 0; if (tsec->sid != sid) { /* Check for shared state. If not ok, leave SID unchanged and kill. */ if (unsafe & LSM_UNSAFE_SHARE) { - rc = avc_has_perm_noaudit(tsec->sid, sid, - SECCLASS_PROCESS, PROCESS__SHARE, &avd); + rc = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, + PROCESS__SHARE, NULL); if (rc) { - task_unlock(current); - avc_audit(tsec->sid, sid, SECCLASS_PROCESS, - PROCESS__SHARE, &avd, rc, NULL); - force_sig_specific(SIGKILL, current); - goto lock_out; + bsec->unsafe = 1; + return; } } /* Check for ptracing, and update the task SID if ok. Otherwise, leave SID unchanged and kill. */ if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { - rc = avc_has_perm_noaudit(tsec->ptrace_sid, sid, - SECCLASS_PROCESS, PROCESS__PTRACE, &avd); - if (!rc) - tsec->sid = sid; - task_unlock(current); - avc_audit(tsec->ptrace_sid, sid, SECCLASS_PROCESS, - PROCESS__PTRACE, &avd, rc, NULL); + rc = avc_has_perm(tsec->ptrace_sid, sid, + SECCLASS_PROCESS, PROCESS__PTRACE, + NULL); if (rc) { - force_sig_specific(SIGKILL, current); - goto lock_out; + bsec->unsafe = 1; + return; } - } else { - tsec->sid = sid; - task_unlock(current); - } - - /* Close files for which the new task SID is not authorized. */ - flush_unauthorized_files(current->files); - - /* Check whether the new SID can inherit signal state - from the old SID. If not, clear itimers to avoid - subsequent signal generation and flush and unblock - signals. This must occur _after_ the task SID has - been updated so that any kill done after the flush - will be checked against the new SID. */ - rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS, - PROCESS__SIGINH, NULL); - if (rc) { - memset(&itimer, 0, sizeof itimer); - for (i = 0; i < 3; i++) - do_setitimer(i, &itimer, NULL); - flush_signals(current); - spin_lock_irq(¤t->sighand->siglock); - flush_signal_handlers(current, 1); - sigemptyset(¤t->blocked); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); } + tsec->sid = sid; + } +} - /* Check whether the new SID can inherit resource limits - from the old SID. If not, reset all soft limits to - the lower of the current task's hard limit and the init - task's soft limit. Note that the setting of hard limits - (even to lower them) can be controlled by the setrlimit - check. The inclusion of the init task's soft limit into - the computation is to avoid resetting soft limits higher - than the default soft limit for cases where the default - is lower than the hard limit, e.g. RLIMIT_CORE or - RLIMIT_STACK.*/ - rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS, - PROCESS__RLIMITINH, NULL); - if (rc) { - for (i = 0; i < RLIM_NLIMITS; i++) { - rlim = current->signal->rlim + i; - initrlim = init_task.signal->rlim+i; - rlim->rlim_cur = min(rlim->rlim_max,initrlim->rlim_cur); - } - } +/* + * called after apply_creds without the task lock held + */ +static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm) +{ + struct task_security_struct *tsec; + struct rlimit *rlim, *initrlim; + struct itimerval itimer; + struct bprm_security_struct *bsec; + int rc, i; - /* Wake up the parent if it is waiting so that it can - recheck wait permission to the new task SID. */ - wake_up_interruptible(¤t->parent->signal->wait_chldexit); + tsec = current->security; + bsec = bprm->security; -lock_out: - task_lock(current); + if (bsec->unsafe) { + force_sig_specific(SIGKILL, current); return; } + if (tsec->osid == tsec->sid) + return; + + /* Close files for which the new task SID is not authorized. */ + flush_unauthorized_files(current->files); + + /* Check whether the new SID can inherit signal state + from the old SID. If not, clear itimers to avoid + subsequent signal generation and flush and unblock + signals. This must occur _after_ the task SID has + been updated so that any kill done after the flush + will be checked against the new SID. */ + rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS, + PROCESS__SIGINH, NULL); + if (rc) { + memset(&itimer, 0, sizeof itimer); + for (i = 0; i < 3; i++) + do_setitimer(i, &itimer, NULL); + flush_signals(current); + spin_lock_irq(¤t->sighand->siglock); + flush_signal_handlers(current, 1); + sigemptyset(¤t->blocked); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } + + /* Check whether the new SID can inherit resource limits + from the old SID. If not, reset all soft limits to + the lower of the current task's hard limit and the init + task's soft limit. Note that the setting of hard limits + (even to lower them) can be controlled by the setrlimit + check. The inclusion of the init task's soft limit into + the computation is to avoid resetting soft limits higher + than the default soft limit for cases where the default + is lower than the hard limit, e.g. RLIMIT_CORE or + RLIMIT_STACK.*/ + rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS, + PROCESS__RLIMITINH, NULL); + if (rc) { + for (i = 0; i < RLIM_NLIMITS; i++) { + rlim = current->signal->rlim + i; + initrlim = init_task.signal->rlim+i; + rlim->rlim_cur = min(rlim->rlim_max,initrlim->rlim_cur); + } + } + + /* Wake up the parent if it is waiting so that it can + recheck wait permission to the new task SID. */ + wake_up_interruptible(¤t->parent->signal->wait_chldexit); } /* superblock security operations */ @@ -4212,6 +4219,7 @@ struct security_operations selinux_ops = { .bprm_alloc_security = selinux_bprm_alloc_security, .bprm_free_security = selinux_bprm_free_security, .bprm_apply_creds = selinux_bprm_apply_creds, + .bprm_post_apply_creds = selinux_bprm_post_apply_creds, .bprm_set_security = selinux_bprm_set_security, .bprm_check_security = selinux_bprm_check_security, .bprm_secureexec = selinux_bprm_secureexec, diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index d1516e47e421..30a0abc9c778 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -87,6 +87,12 @@ struct bprm_security_struct { struct linux_binprm *bprm; /* back pointer to bprm object */ u32 sid; /* SID for transformed process */ unsigned char set; + + /* + * unsafe is used to share failure information from bprm_apply_creds() + * to bprm_post_apply_creds(). + */ + char unsafe; }; struct netif_security_struct { -- cgit v1.2.3 From b6dfc3f2d6cb1a1d0c1ad4506712c1557566b419 Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Mon, 10 Jan 2005 17:10:53 -0800 Subject: [PATCH] merge *_vm_enough_memory()s into a common helper The vm_enough_memory functionality was replicated in three separate places, and not always kept in sync. It also used capable() for authorization checks. This caused any process which ends up checking for this permission to have PF_SUPERPRIV set (inappropriately), and caused poor dependencies between stacked modules, since each LSM was generically asked to moderate capable(CAP_SYS_ADMIN) without knowing why. Signed-off-by: Serge Hallyn Signed-off-by: Chris Wright Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 1 + mm/mmap.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ security/commoncap.c | 81 +++----------------------------------------- security/dummy.c | 64 +++-------------------------------- security/selinux/hooks.c | 70 +++++++++----------------------------- 5 files changed, 112 insertions(+), 192 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mm.h b/include/linux/mm.h index ee9817135376..75f5b8ed7231 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -711,6 +711,7 @@ static inline void vma_nonlinear_insert(struct vm_area_struct *vma, } /* mmap.c */ +extern int __vm_enough_memory(long pages, int cap_sys_admin); extern void vma_adjust(struct vm_area_struct *vma, unsigned long start, unsigned long end, pgoff_t pgoff, struct vm_area_struct *insert); extern struct vm_area_struct *vma_merge(struct mm_struct *, diff --git a/mm/mmap.c b/mm/mmap.c index ca45a0e92e3b..f0d1f464ee00 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -61,10 +61,98 @@ int sysctl_overcommit_ratio = 50; /* default is 50% */ int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT; atomic_t vm_committed_space = ATOMIC_INIT(0); +/* + * Check that a process has enough memory to allocate a new virtual + * mapping. 0 means there is enough memory for the allocation to + * succeed and -ENOMEM implies there is not. + * + * We currently support three overcommit policies, which are set via the + * vm.overcommit_memory sysctl. See Documentation/vm/overcommit-accounting + * + * Strict overcommit modes added 2002 Feb 26 by Alan Cox. + * Additional code 2002 Jul 20 by Robert Love. + * + * cap_sys_admin is 1 if the process has admin privileges, 0 otherwise. + * + * Note this is a helper function intended to be used by LSMs which + * wish to use this logic. + */ +int __vm_enough_memory(long pages, int cap_sys_admin) +{ + unsigned long free, allowed; + + vm_acct_memory(pages); + + /* + * Sometimes we want to use more memory than we have + */ + if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS) + return 0; + + if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) { + unsigned long n; + + free = get_page_cache_size(); + free += nr_swap_pages; + + /* + * Any slabs which are created with the + * SLAB_RECLAIM_ACCOUNT flag claim to have contents + * which are reclaimable, under pressure. The dentry + * cache and most inode caches should fall into this + */ + free += atomic_read(&slab_reclaim_pages); + + /* + * Leave the last 3% for root + */ + if (!cap_sys_admin) + free -= free / 32; + + if (free > pages) + return 0; + + /* + * nr_free_pages() is very expensive on large systems, + * only call if we're about to fail. + */ + n = nr_free_pages(); + if (!cap_sys_admin) + n -= n / 32; + free += n; + + if (free > pages) + return 0; + vm_unacct_memory(pages); + return -ENOMEM; + } + + allowed = (totalram_pages - hugetlb_total_pages()) + * sysctl_overcommit_ratio / 100; + /* + * Leave the last 3% for root + */ + if (!cap_sys_admin) + allowed -= allowed / 32; + allowed += total_swap_pages; + + /* Don't let a single process grow too big: + leave 3% of the size of this process for other processes */ + allowed -= current->mm->total_vm / 32; + + if (atomic_read(&vm_committed_space) < allowed) + return 0; + + vm_unacct_memory(pages); + + return -ENOMEM; +} + EXPORT_SYMBOL(sysctl_overcommit_memory); EXPORT_SYMBOL(sysctl_overcommit_ratio); EXPORT_SYMBOL(sysctl_max_map_count); EXPORT_SYMBOL(vm_committed_space); +EXPORT_SYMBOL(__vm_enough_memory); /* * Requires inode->i_mapping->i_mmap_lock diff --git a/security/commoncap.c b/security/commoncap.c index 0fdbcfd40a98..849b8c338ee8 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -316,86 +316,13 @@ int cap_syslog (int type) return 0; } -/* - * Check that a process has enough memory to allocate a new virtual - * mapping. 0 means there is enough memory for the allocation to - * succeed and -ENOMEM implies there is not. - * - * We currently support three overcommit policies, which are set via the - * vm.overcommit_memory sysctl. See Documentation/vm/overcommit-accounting - * - * Strict overcommit modes added 2002 Feb 26 by Alan Cox. - * Additional code 2002 Jul 20 by Robert Love. - */ int cap_vm_enough_memory(long pages) { - unsigned long free, allowed; - - vm_acct_memory(pages); - - /* - * Sometimes we want to use more memory than we have - */ - if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS) - return 0; - - if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) { - unsigned long n; - - free = get_page_cache_size(); - free += nr_swap_pages; - - /* - * Any slabs which are created with the - * SLAB_RECLAIM_ACCOUNT flag claim to have contents - * which are reclaimable, under pressure. The dentry - * cache and most inode caches should fall into this - */ - free += atomic_read(&slab_reclaim_pages); - - /* - * Leave the last 3% for root - */ - if (!capable(CAP_SYS_ADMIN)) - free -= free / 32; - - if (free > pages) - return 0; - - /* - * nr_free_pages() is very expensive on large systems, - * only call if we're about to fail. - */ - n = nr_free_pages(); - if (!capable(CAP_SYS_ADMIN)) - n -= n / 32; - free += n; - - if (free > pages) - return 0; - vm_unacct_memory(pages); - return -ENOMEM; - } - - allowed = (totalram_pages - hugetlb_total_pages()) - * sysctl_overcommit_ratio / 100; - /* - * Leave the last 3% for root - */ - if (!capable(CAP_SYS_ADMIN)) - allowed -= allowed / 32; - allowed += total_swap_pages; - - /* Don't let a single process grow too big: - leave 3% of the size of this process for other processes */ - allowed -= current->mm->total_vm / 32; - - if (atomic_read(&vm_committed_space) < allowed) - return 0; - - vm_unacct_memory(pages); + int cap_sys_admin = 0; - return -ENOMEM; + if (cap_capable(current, CAP_SYS_ADMIN) == 0) + cap_sys_admin = 1; + return __vm_enough_memory(pages, cap_sys_admin); } EXPORT_SYMBOL(cap_capable); diff --git a/security/dummy.c b/security/dummy.c index 16d48b15ca1b..72e6d71a79aa 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -108,69 +108,13 @@ static int dummy_settime(struct timespec *ts, struct timezone *tz) return 0; } -/* - * Check that a process has enough memory to allocate a new virtual - * mapping. 0 means there is enough memory for the allocation to - * succeed and -ENOMEM implies there is not. - * - * We currently support three overcommit policies, which are set via the - * vm.overcommit_memory sysctl. See Documentation/vm/overcommit-accounting - */ static int dummy_vm_enough_memory(long pages) { - unsigned long free, allowed; - - vm_acct_memory(pages); - - /* - * Sometimes we want to use more memory than we have - */ - if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS) - return 0; - - if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) { - free = get_page_cache_size(); - free += nr_free_pages(); - free += nr_swap_pages; - - /* - * Any slabs which are created with the - * SLAB_RECLAIM_ACCOUNT flag claim to have contents - * which are reclaimable, under pressure. The dentry - * cache and most inode caches should fall into this - */ - free += atomic_read(&slab_reclaim_pages); - - /* - * Leave the last 3% for root - */ - if (current->euid) - free -= free / 32; - - if (free > pages) - return 0; - vm_unacct_memory(pages); - return -ENOMEM; - } - - allowed = (totalram_pages - hugetlb_total_pages()) - * sysctl_overcommit_ratio / 100; - allowed += total_swap_pages; - - /* Leave the last 3% for root */ - if (current->euid) - allowed -= allowed / 32; - - /* Don't let a single process grow too big: - leave 3% of the size of this process for other processes */ - allowed -= current->mm->total_vm / 32; - - if (atomic_read(&vm_committed_space) < allowed) - return 0; - - vm_unacct_memory(pages); + int cap_sys_admin = 0; - return -ENOMEM; + if (dummy_capable(current, CAP_SYS_ADMIN) == 0) + cap_sys_admin = 1; + return __vm_enough_memory(pages, cap_sys_admin); } static int dummy_bprm_alloc_security (struct linux_binprm *bprm) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 2cbabb33c2a9..ea244b769d99 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1515,69 +1515,29 @@ static int selinux_syslog(int type) * mapping. 0 means there is enough memory for the allocation to * succeed and -ENOMEM implies there is not. * - * We currently support three overcommit policies, which are set via the - * vm.overcommit_memory sysctl. See Documentation/vm/overcommit-accounting + * Note that secondary_ops->capable and task_has_perm_noaudit return 0 + * if the capability is granted, but __vm_enough_memory requires 1 if + * the capability is granted. * - * Strict overcommit modes added 2002 Feb 26 by Alan Cox. - * Additional code 2002 Jul 20 by Robert Love. + * Do not audit the selinux permission check, as this is applied to all + * processes that allocate mappings. */ static int selinux_vm_enough_memory(long pages) { - unsigned long free, allowed; - int rc; + int rc, cap_sys_admin = 0; struct task_security_struct *tsec = current->security; - vm_acct_memory(pages); - - /* - * Sometimes we want to use more memory than we have - */ - if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS) - return 0; - - if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) { - free = get_page_cache_size(); - free += nr_free_pages(); - free += nr_swap_pages; - - /* - * Any slabs which are created with the - * SLAB_RECLAIM_ACCOUNT flag claim to have contents - * which are reclaimable, under pressure. The dentry - * cache and most inode caches should fall into this - */ - free += atomic_read(&slab_reclaim_pages); - - /* - * Leave the last 3% for privileged processes. - * Don't audit the check, as it is applied to all processes - * that allocate mappings. - */ - rc = secondary_ops->capable(current, CAP_SYS_ADMIN); - if (!rc) { - rc = avc_has_perm_noaudit(tsec->sid, tsec->sid, - SECCLASS_CAPABILITY, - CAP_TO_MASK(CAP_SYS_ADMIN), NULL); - } - if (rc) - free -= free / 32; - - if (free > pages) - return 0; - vm_unacct_memory(pages); - return -ENOMEM; - } - - allowed = (totalram_pages - hugetlb_total_pages()) - * sysctl_overcommit_ratio / 100; - allowed += total_swap_pages; - - if (atomic_read(&vm_committed_space) < allowed) - return 0; + rc = secondary_ops->capable(current, CAP_SYS_ADMIN); + if (rc == 0) + rc = avc_has_perm_noaudit(tsec->sid, tsec->sid, + SECCLASS_CAPABILITY, + CAP_TO_MASK(CAP_SYS_ADMIN), + NULL); - vm_unacct_memory(pages); + if (rc == 0) + cap_sys_admin = 1; - return -ENOMEM; + return __vm_enough_memory(pages, cap_sys_admin); } /* binprm security operations */ -- cgit v1.2.3 From 3f3078b6fd65b26f1fbfca470d5e85479b48a64e Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Mon, 10 Jan 2005 17:12:03 -0800 Subject: [PATCH] pm: introduce pm_message_t This introduces pm_message_t. For now, it is only good for type-safety and sparse checking, but plan is to turn pm_message_t into structure soon. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/power/devices.txt | 88 +++++++++++++++++++++++++++++++++++++++++ arch/arm/common/amba.c | 2 +- arch/arm/common/locomo.c | 2 +- arch/arm/common/sa1111.c | 2 +- drivers/base/platform.c | 2 +- drivers/base/power/power.h | 6 +-- drivers/base/power/runtime.c | 4 +- drivers/base/power/suspend.c | 8 ++-- drivers/ide/ide.c | 2 +- drivers/pci/pci-driver.c | 2 +- include/linux/device.h | 2 +- include/linux/pm.h | 32 +++++++++++++-- 12 files changed, 132 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt index 435ea29bb676..2b2a3a6f96e2 100644 --- a/Documentation/power/devices.txt +++ b/Documentation/power/devices.txt @@ -118,6 +118,94 @@ will fail. There is currently no way to know what states a device or driver supports a priori. This will change in the future. +pm_message_t meaning + +pm_message_t has two fields. event ("major"), and flags. If driver +does not know event code, it aborts the request, returning error. Some +drivers may need to deal with special cases based on the actual type +of suspend operation being done at the system level. This is why +there are flags. + +Event codes are: + +ON -- no need to do anything except special cases like broken +HW. + +# NOTIFICATION -- pretty much same as ON? + +FREEZE -- stop DMA and interrupts, and be prepared to reinit HW from +scratch. That probably means stop accepting upstream requests, the +actual policy of what to do with them beeing specific to a given +driver. It's acceptable for a network driver to just drop packets +while a block driver is expected to block the queue so no request is +lost. (Use IDE as an example on how to do that). FREEZE requires no +power state change, and it's expected for drivers to be able to +quickly transition back to operating state. + +SUSPEND -- like FREEZE, but also put hardware into low-power state. If +there's need to distinguish several levels of sleep, additional flag +is probably best way to do that. + +Transitions are only from a resumed state to a suspended state, never +between 2 suspended states. (ON -> FREEZE or ON -> SUSPEND can happen, +FREEZE -> SUSPEND or SUSPEND -> FREEZE can not). + +All events are: + +[NOTE NOTE NOTE: If you are driver author, you should not care; you +should only look at event, and ignore flags.] + +#Prepare for suspend -- userland is still running but we are going to +#enter suspend state. This gives drivers chance to load firmware from +#disk and store it in memory, or do other activities taht require +#operating userland, ability to kmalloc GFP_KERNEL, etc... All of these +#are forbiden once the suspend dance is started.. event = ON, flags = +#PREPARE_TO_SUSPEND + +Apm standby -- prepare for APM event. Quiesce devices to make life +easier for APM BIOS. event = FREEZE, flags = APM_STANDBY + +Apm suspend -- same as APM_STANDBY, but it we should probably avoid +spinning down disks. event = FREEZE, flags = APM_SUSPEND + +System halt, reboot -- quiesce devices to make life easier for BIOS. event += FREEZE, flags = SYSTEM_HALT or SYSTEM_REBOOT + +System shutdown -- at least disks need to be spun down, or data may be +lost. Quiesce devices, just to make life easier for BIOS. event = +FREEZE, flags = SYSTEM_SHUTDOWN + +Kexec -- turn off DMAs and put hardware into some state where new +kernel can take over. event = FREEZE, flags = KEXEC + +Powerdown at end of swsusp -- very similar to SYSTEM_SHUTDOWN, except wake +may need to be enabled on some devices. This actually has at least 3 +subtypes, system can reboot, enter S4 and enter S5 at the end of +swsusp. event = FREEZE, flags = SWSUSP and one of SYSTEM_REBOOT, +SYSTEM_SHUTDOWN, SYSTEM_S4 + +Suspend to ram -- put devices into low power state. event = SUSPEND, +flags = SUSPEND_TO_RAM + +Freeze for swsusp snapshot -- stop DMA and interrupts. No need to put +devices into low power mode, but you must be able to reinitialize +device from scratch in resume method. This has two flavors, its done +once on suspending kernel, once on resuming kernel. event = FREEZE, +flags = DURING_SUSPEND or DURING_RESUME + +Device detach requested from /sys -- deinitialize device; proably same as +SYSTEM_SHUTDOWN, I do not understand this one too much. probably event += FREEZE, flags = DEV_DETACH. + +#These are not really events sent: +# +#System fully on -- device is working normally; this is probably never +#passed to suspend() method... event = ON, flags = 0 +# +#Ready after resume -- userland is now running, again. Time to free any +#memory you ate during prepare to suspend... event = ON, flags = +#READY_AFTER_RESUME +# Driver Detach Power Management diff --git a/arch/arm/common/amba.c b/arch/arm/common/amba.c index b5f5c6d2cb62..a0507f8c33fe 100644 --- a/arch/arm/common/amba.c +++ b/arch/arm/common/amba.c @@ -59,7 +59,7 @@ static int amba_hotplug(struct device *dev, char **envp, int nr_env, char *buf, #define amba_hotplug NULL #endif -static int amba_suspend(struct device *dev, u32 state) +static int amba_suspend(struct device *dev, pm_message_t state) { struct amba_driver *drv = to_amba_driver(dev->driver); int ret = 0; diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c index b86e288c678c..34c8cf33ad9a 100644 --- a/arch/arm/common/locomo.c +++ b/arch/arm/common/locomo.c @@ -668,7 +668,7 @@ static int locomo_match(struct device *_dev, struct device_driver *_drv) return dev->devid == drv->devid; } -static int locomo_bus_suspend(struct device *dev, u32 state) +static int locomo_bus_suspend(struct device *dev, pm_message_t state) { struct locomo_dev *ldev = LOCOMO_DEV(dev); struct locomo_driver *drv = LOCOMO_DRV(dev->driver); diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 32839b819c34..c90939341db1 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -1193,7 +1193,7 @@ static int sa1111_match(struct device *_dev, struct device_driver *_drv) return dev->devid == drv->devid; } -static int sa1111_bus_suspend(struct device *dev, u32 state) +static int sa1111_bus_suspend(struct device *dev, pm_message_t state) { struct sa1111_dev *sadev = SA1111_DEV(dev); struct sa1111_driver *drv = SA1111_DRV(dev->driver); diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 81251fde2516..c8c87cebcbc1 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -276,7 +276,7 @@ static int platform_match(struct device * dev, struct device_driver * drv) return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0); } -static int platform_suspend(struct device * dev, u32 state) +static int platform_suspend(struct device * dev, pm_message_t state) { int ret = 0; diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 66cb431b1433..e5eda746f2a6 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -71,14 +71,14 @@ extern int resume_device(struct device *); /* * suspend.c */ -extern int suspend_device(struct device *, u32); +extern int suspend_device(struct device *, pm_message_t); /* * runtime.c */ -extern int dpm_runtime_suspend(struct device *, u32); +extern int dpm_runtime_suspend(struct device *, pm_message_t); extern void dpm_runtime_resume(struct device *); #else /* CONFIG_PM */ @@ -93,7 +93,7 @@ static inline void device_pm_remove(struct device * dev) } -static inline int dpm_runtime_suspend(struct device * dev, u32 state) +static inline int dpm_runtime_suspend(struct device * dev, pm_message_t state) { return 0; } diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 5e58f68363af..325962d80191 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -44,7 +44,7 @@ void dpm_runtime_resume(struct device * dev) * @state: State to enter. */ -int dpm_runtime_suspend(struct device * dev, u32 state) +int dpm_runtime_suspend(struct device * dev, pm_message_t state) { int error = 0; @@ -73,7 +73,7 @@ int dpm_runtime_suspend(struct device * dev, u32 state) * always be able to tell, but we need accurate information to * work reliably. */ -void dpm_set_power_state(struct device * dev, u32 state) +void dpm_set_power_state(struct device * dev, pm_message_t state) { down(&dpm_sem); dev->power.power_state = state; diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index 94c1311ee26b..8e1ace2d817e 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c @@ -11,7 +11,7 @@ #include #include "power.h" -extern int sysdev_suspend(u32 state); +extern int sysdev_suspend(pm_message_t state); /* * The entries in the dpm_active list are in a depth first order, simply @@ -35,7 +35,7 @@ extern int sysdev_suspend(u32 state); * @state: Power state device is entering. */ -int suspend_device(struct device * dev, u32 state) +int suspend_device(struct device * dev, pm_message_t state) { int error = 0; @@ -65,7 +65,7 @@ int suspend_device(struct device * dev, u32 state) * */ -int device_suspend(u32 state) +int device_suspend(pm_message_t state) { int error = 0; @@ -118,7 +118,7 @@ EXPORT_SYMBOL_GPL(device_suspend); * done, power down system devices. */ -int device_power_down(u32 state) +int device_power_down(pm_message_t state) { int error = 0; struct device * dev; diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 2e50f8597b83..7f867df01a56 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1380,7 +1380,7 @@ int ata_attach(ide_drive_t *drive) return 1; } -static int generic_ide_suspend(struct device *dev, u32 state) +static int generic_ide_suspend(struct device *dev, pm_message_t state) { ide_drive_t *drive = dev->driver_data; struct request rq; diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 7ce952cd99f6..7371987cf183 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -284,7 +284,7 @@ static int pci_device_remove(struct device * dev) return 0; } -static int pci_device_suspend(struct device * dev, u32 state) +static int pci_device_suspend(struct device * dev, pm_message_t state) { struct pci_dev * pci_dev = to_pci_dev(dev); struct pci_driver * drv = pci_dev->driver; diff --git a/include/linux/device.h b/include/linux/device.h index 2c5d57283d5a..786e1591102b 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -61,7 +61,7 @@ struct bus_type { int (*match)(struct device * dev, struct device_driver * drv); int (*hotplug) (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); - int (*suspend)(struct device * dev, u32 state); + int (*suspend)(struct device * dev, pm_message_t state); int (*resume)(struct device * dev); }; diff --git a/include/linux/pm.h b/include/linux/pm.h index 68da2eae8547..22c7aeb6419e 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -222,10 +222,34 @@ extern int pm_suspend(suspend_state_t state); struct device; +typedef u32 __bitwise pm_message_t; + +/* + * There are 4 important states driver can be in: + * ON -- driver is working + * FREEZE -- stop operations and apply whatever policy is applicable to a suspended driver + * of that class, freeze queues for block like IDE does, drop packets for + * ethernet, etc... stop DMA engine too etc... so a consistent image can be + * saved; but do not power any hardware down. + * SUSPEND - like FREEZE, but hardware is doing as much powersaving as possible. Roughly + * pci D3. + * + * Unfortunately, current drivers only recognize numeric values 0 (ON) and 3 (SUSPEND). + * We'll need to fix the drivers. So yes, putting 3 to all diferent defines is intentional, + * and will go away as soon as drivers are fixed. Also note that typedef is neccessary, + * we'll probably want to switch to + * typedef struct pm_message_t { int event; int flags; } pm_message_t + * or something similar soon. + */ + +#define PMSG_FREEZE ((__force pm_message_t) 3) +#define PMSG_SUSPEND ((__force pm_message_t) 3) +#define PMSG_ON ((__force pm_message_t) 0) + struct dev_pm_info { - u32 power_state; + pm_message_t power_state; #ifdef CONFIG_PM - u32 prev_state; + pm_message_t prev_state; void * saved_state; atomic_t pm_users; struct device * pm_parent; @@ -235,8 +259,8 @@ struct dev_pm_info { extern void device_pm_set_parent(struct device * dev, struct device * parent); -extern int device_suspend(u32 state); -extern int device_power_down(u32 state); +extern int device_suspend(pm_message_t state); +extern int device_power_down(pm_message_t state); extern void device_power_up(void); extern void device_resume(void); -- cgit v1.2.3 From bf17b0cb528a4ccafbd969bfbcef85a2fa2006bf Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Mon, 10 Jan 2005 17:12:19 -0800 Subject: [PATCH] mark older power managment as deprecated Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/pm.h | 71 +++++++++++++++++------------------------------------- 1 file changed, 22 insertions(+), 49 deletions(-) (limited to 'include/linux') diff --git a/include/linux/pm.h b/include/linux/pm.h index 22c7aeb6419e..1d106a3edad5 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -28,44 +28,28 @@ #include /* - * Power management requests + * Power management requests... these are passed to pm_send_all() and friends. + * + * these functions are old and deprecated, see below. */ -enum -{ - PM_SUSPEND, /* enter D1-D3 */ - PM_RESUME, /* enter D0 */ - - PM_SAVE_STATE, /* save device's state */ +typedef int __bitwise pm_request_t; - /* enable wake-on */ - PM_SET_WAKEUP, +#define PM_SUSPEND ((__force pm_request_t) 1) /* enter D1-D3 */ +#define PM_RESUME ((__force pm_request_t) 2) /* enter D0 */ - /* bus resource management */ - PM_GET_RESOURCES, - PM_SET_RESOURCES, - - /* base station management */ - PM_EJECT, - PM_LOCK, -}; - -typedef int pm_request_t; /* - * Device types + * Device types... these are passed to pm_register */ -enum -{ - PM_UNKNOWN_DEV = 0, /* generic */ - PM_SYS_DEV, /* system device (fan, KB controller, ...) */ - PM_PCI_DEV, /* PCI device */ - PM_USB_DEV, /* USB device */ - PM_SCSI_DEV, /* SCSI device */ - PM_ISA_DEV, /* ISA device */ - PM_MTD_DEV, /* Memory Technology Device */ -}; +typedef int __bitwise pm_dev_t; -typedef int pm_dev_t; +#define PM_UNKNOWN_DEV ((__force pm_dev_t) 0) /* generic */ +#define PM_SYS_DEV ((__force pm_dev_t) 1) /* system device (fan, KB controller, ...) */ +#define PM_PCI_DEV ((__force pm_dev_t) 2) /* PCI device */ +#define PM_USB_DEV ((__force pm_dev_t) 3) /* USB device */ +#define PM_SCSI_DEV ((__force pm_dev_t) 4) /* SCSI device */ +#define PM_ISA_DEV ((__force pm_dev_t) 5) /* ISA device */ +#define PM_MTD_DEV ((__force pm_dev_t) 6) /* Memory Technology Device */ /* * System device hardware ID (PnP) values @@ -119,32 +103,27 @@ extern int pm_active; /* * Register a device with power management */ -struct pm_dev *pm_register(pm_dev_t type, - unsigned long id, - pm_callback callback); +struct pm_dev __deprecated *pm_register(pm_dev_t type, unsigned long id, pm_callback callback); /* * Unregister a device with power management */ -void pm_unregister(struct pm_dev *dev); +void __deprecated pm_unregister(struct pm_dev *dev); /* * Unregister all devices with matching callback */ -void pm_unregister_all(pm_callback callback); +void __deprecated pm_unregister_all(pm_callback callback); /* * Send a request to a single device */ -int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data); +int __deprecated pm_send(struct pm_dev *dev, pm_request_t rqst, void *data); /* * Send a request to all devices */ -int pm_send_all(pm_request_t rqst, void *data); - -static inline void pm_access(struct pm_dev *dev) {} -static inline void pm_dev_idle(struct pm_dev *dev) {} +int __deprecated pm_send_all(pm_request_t rqst, void *data); #else /* CONFIG_PM */ @@ -171,16 +150,10 @@ static inline int pm_send_all(pm_request_t rqst, void *data) return 0; } -static inline struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from) -{ - return 0; -} - -static inline void pm_access(struct pm_dev *dev) {} -static inline void pm_dev_idle(struct pm_dev *dev) {} - #endif /* CONFIG_PM */ +/* Functions above this comment are list-based old-style power + * managment. Please avoid using them. */ /* * Callbacks for platform drivers to implement. -- cgit v1.2.3 From a4a2d10db6c1e1ba2fe5077bc263b8d0254e6933 Mon Sep 17 00:00:00 2001 From: Mike Miller Date: Mon, 10 Jan 2005 17:14:45 -0800 Subject: [PATCH] cciss update to version 2.6.4 This patch removes support for 2 controllers that were recently cancelled and it adds support for the P600, a cciss based SAS controller due to ship in late March/early April '05. Neither of these controllers have made it to the field. Signed-off-by: Mike Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/cciss.txt | 3 +-- drivers/block/cciss.c | 17 +++++++---------- include/linux/pci_ids.h | 2 +- 3 files changed, 9 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/Documentation/cciss.txt b/Documentation/cciss.txt index aadd46fc3001..74589c53a0c4 100644 --- a/Documentation/cciss.txt +++ b/Documentation/cciss.txt @@ -14,8 +14,7 @@ This driver is known to work with the following cards: * SA 6400 * SA 6400 U320 Expansion Module * SA 6i - * SA 6422 - * SA V100 + * SA P600 If nodes are not already created in the /dev/cciss directory, run as root: diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index f747fb3d13db..2f30018d3387 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -46,14 +46,14 @@ #include #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "HP CISS Driver (v 2.6.2)" -#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,2) +#define DRIVER_NAME "HP CISS Driver (v 2.6.4)" +#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,4) /* Embedded module documentation macros - see modules.h */ MODULE_AUTHOR("Hewlett-Packard Company"); -MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.2"); +MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.4"); MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400" - " SA6i V100"); + " SA6i P600"); MODULE_LICENSE("GPL"); #include "cciss_cmd.h" @@ -80,10 +80,8 @@ const struct pci_device_id cciss_pci_device_id[] = { 0x0E11, 0x409D, 0, 0, 0}, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x4091, 0, 0, 0}, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, - 0x0E11, 0x409E, 0, 0, 0}, - { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISS, - 0x103C, 0x3211, 0, 0, 0}, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA, + 0x103C, 0x3225, 0, 0, 0}, {0,} }; MODULE_DEVICE_TABLE(pci, cciss_pci_device_id); @@ -104,8 +102,7 @@ static struct board_type products[] = { { 0x409C0E11, "Smart Array 6400", &SA5_access}, { 0x409D0E11, "Smart Array 6400 EM", &SA5_access}, { 0x40910E11, "Smart Array 6i", &SA5_access}, - { 0x409E0E11, "Smart Array 6422", &SA5_access}, - { 0x3211103C, "Smart Array V100", &SA5_access}, + { 0x3225103C, "Smart Array P600", &SA5_access}, }; /* How long to wait (in millesconds) for board to go into simple mode */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index f36775e68710..791a795862c2 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -693,7 +693,7 @@ #define PCI_DEVICE_ID_HP_SX1000_IOC 0x127c #define PCI_DEVICE_ID_HP_DIVA_EVEREST 0x1282 #define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290 -#define PCI_DEVICE_ID_HP_CISS 0x3210 +#define PCI_DEVICE_ID_HP_CISSA 0x3220 #define PCI_VENDOR_ID_PCTECH 0x1042 #define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000 -- cgit v1.2.3 From 67547e35e2802ad9e2ad8c5e7fccb61ac12ce4e7 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 10 Jan 2005 17:18:41 -0800 Subject: [PATCH] optimize prefetch() usage in list_for_each_xxx This patch changes list_for_each_xxx iterators from: for (pos = (head)->next, prefetch(pos->next); pos != (head); pos = pos->next, prefetch(pos->next)) to: for (pos = (head)->next; prefetch(pos->next), pos != (head); pos = pos->next) Reduces my vmlinux .text size by 4401 bytes. Signed-off-by: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/list.h | 48 ++++++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/include/linux/list.h b/include/linux/list.h index 7cad5322077c..dd7cd54fa831 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -326,8 +326,8 @@ static inline void list_splice_init(struct list_head *list, * @head: the head for your list. */ #define list_for_each(pos, head) \ - for (pos = (head)->next, prefetch(pos->next); pos != (head); \ - pos = pos->next, prefetch(pos->next)) + for (pos = (head)->next; prefetch(pos->next), pos != (head); \ + pos = pos->next) /** * __list_for_each - iterate over a list @@ -348,8 +348,8 @@ static inline void list_splice_init(struct list_head *list, * @head: the head for your list. */ #define list_for_each_prev(pos, head) \ - for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ - pos = pos->prev, prefetch(pos->prev)) + for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ + pos = pos->prev) /** * list_for_each_safe - iterate over a list safe against removal of list entry @@ -368,11 +368,9 @@ static inline void list_splice_init(struct list_head *list, * @member: the name of the list_struct within the struct. */ #define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - prefetch(pos->member.next); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member), \ - prefetch(pos->member.next)) + for (pos = list_entry((head)->next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_reverse - iterate backwards over list of given type. @@ -381,11 +379,9 @@ static inline void list_splice_init(struct list_head *list, * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - prefetch(pos->member.prev); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member), \ - prefetch(pos->member.prev)) + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) /** * list_prepare_entry - prepare a pos entry for use as a start point in @@ -405,11 +401,9 @@ static inline void list_splice_init(struct list_head *list, * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - prefetch(pos->member.next); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member), \ - prefetch(pos->member.next)) + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry @@ -434,8 +428,8 @@ static inline void list_splice_init(struct list_head *list, * as long as the traversal is guarded by rcu_read_lock(). */ #define list_for_each_rcu(pos, head) \ - for (pos = (head)->next, prefetch(pos->next); pos != (head); \ - pos = rcu_dereference(pos->next), prefetch(pos->next)) + for (pos = (head)->next; prefetch(pos->next), pos != (head); \ + pos = rcu_dereference(pos->next)) #define __list_for_each_rcu(pos, head) \ for (pos = (head)->next; pos != (head); \ @@ -467,12 +461,10 @@ static inline void list_splice_init(struct list_head *list, * as long as the traversal is guarded by rcu_read_lock(). */ #define list_for_each_entry_rcu(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - prefetch(pos->member.next); \ - &pos->member != (head); \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ pos = rcu_dereference(list_entry(pos->member.next, \ - typeof(*pos), member)), \ - prefetch(pos->member.next)) + typeof(*pos), member))) /** @@ -486,8 +478,8 @@ static inline void list_splice_init(struct list_head *list, * as long as the traversal is guarded by rcu_read_lock(). */ #define list_for_each_continue_rcu(pos, head) \ - for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \ - (pos) = rcu_dereference((pos)->next), prefetch((pos)->next)) + for ((pos) = (pos)->next; prefetch((pos)->next), (pos) != (head); \ + (pos) = rcu_dereference((pos)->next)) /* * Double linked lists with a single pointer list head. -- cgit v1.2.3 From 77aa6cbfb03f4bc3a3e9676efcd24879946438c4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 10 Jan 2005 17:20:37 -0800 Subject: [PATCH] cleanup virtual console <-> selection.c interface Pass around pointers instead of indices into a global array between various files of the virtual console implementation and stop using obsfucting macros that expect certain variables to be in scope. This is a first step to get rid of the various global arrays in the VC code. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/selection.c | 44 +++-- drivers/char/vc_screen.c | 60 +++--- drivers/char/vt.c | 428 +++++++++++++++++++++-------------------- drivers/char/vt_ioctl.c | 2 +- include/linux/console_struct.h | 3 + include/linux/selection.h | 23 +-- 6 files changed, 284 insertions(+), 276 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/selection.c b/drivers/char/selection.c index 0c265fe6713a..791b1fc1f4a0 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c @@ -33,7 +33,7 @@ extern void poke_blanked_console(void); /* Variables for selection control. */ /* Use a dynamic buffer, instead of static (Dec 1994) */ - int sel_cons; /* must not be disallocated */ +struct vc_data *sel_cons; /* must not be disallocated */ static volatile int sel_start = -1; /* cleared by clear_selection */ static int sel_end; static int sel_buffer_lth; @@ -44,20 +44,22 @@ static char *sel_buffer; /* set reverse video on characters s-e of console with selection. */ inline static void -highlight(const int s, const int e) { +highlight(const int s, const int e) +{ invert_screen(sel_cons, s, e-s+2, 1); } /* use complementary color to show the pointer */ inline static void -highlight_pointer(const int where) { +highlight_pointer(const int where) +{ complement_pos(sel_cons, where); } static unsigned char sel_pos(int n) { - return inverse_translate(vc_cons[sel_cons].d, screen_glyph(sel_cons, n)); + return inverse_translate(sel_cons, screen_glyph(sel_cons, n)); } /* remove the current selection highlight, if any, @@ -111,10 +113,10 @@ static inline unsigned short limit(const unsigned short v, const unsigned short /* set the current selection. Invoked by ioctl() or by kernel code. */ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) { + struct vc_data *vc = vc_cons[fg_console].d; int sel_mode, new_sel_start, new_sel_end, spc; char *bp, *obp; int i, ps, pe; - unsigned int currcons = fg_console; poke_blanked_console(); @@ -128,12 +130,12 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t __get_user(ye, &sel->ye); __get_user(sel_mode, &sel->sel_mode); xs--; ys--; xe--; ye--; - xs = limit(xs, video_num_columns - 1); - ys = limit(ys, video_num_lines - 1); - xe = limit(xe, video_num_columns - 1); - ye = limit(ye, video_num_lines - 1); - ps = ys * video_size_row + (xs << 1); - pe = ye * video_size_row + (xe << 1); + xs = limit(xs, vc->vc_cols - 1); + ys = limit(ys, vc->vc_rows - 1); + xe = limit(xe, vc->vc_cols - 1); + ye = limit(ye, vc->vc_rows - 1); + ps = ys * vc->vc_size_row + (xs << 1); + pe = ye * vc->vc_size_row + (xe << 1); if (sel_mode == TIOCL_SELCLEAR) { /* useful for screendump without selection highlights */ @@ -154,9 +156,9 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t pe = tmp; } - if (sel_cons != fg_console) { + if (sel_cons != vc_cons[fg_console].d) { clear_selection(); - sel_cons = fg_console; + sel_cons = vc_cons[fg_console].d; } switch (sel_mode) @@ -173,7 +175,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t (!spc && !inword(sel_pos(ps)))) break; new_sel_start = ps; - if (!(ps % video_size_row)) + if (!(ps % vc->vc_size_row)) break; } spc = isspace(sel_pos(pe)); @@ -183,14 +185,14 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t (!spc && !inword(sel_pos(pe)))) break; new_sel_end = pe; - if (!((pe + 2) % video_size_row)) + if (!((pe + 2) % vc->vc_size_row)) break; } break; case TIOCL_SELLINE: /* line-by-line selection */ - new_sel_start = ps - ps % video_size_row; - new_sel_end = pe + video_size_row - - pe % video_size_row - 2; + new_sel_start = ps - ps % vc->vc_size_row; + new_sel_end = pe + vc->vc_size_row + - pe % vc->vc_size_row - 2; break; case TIOCL_SELPOINTER: highlight_pointer(pe); @@ -204,11 +206,11 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t /* select to end of line if on trailing space */ if (new_sel_end > new_sel_start && - !atedge(new_sel_end, video_size_row) && + !atedge(new_sel_end, vc->vc_size_row) && isspace(sel_pos(new_sel_end))) { for (pe = new_sel_end + 2; ; pe += 2) if (!isspace(sel_pos(pe)) || - atedge(pe, video_size_row)) + atedge(pe, vc->vc_size_row)) break; if (isspace(sel_pos(pe))) new_sel_end = pe; @@ -255,7 +257,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t *bp = sel_pos(i); if (!isspace(*bp++)) obp = bp; - if (! ((i + 2) % video_size_row)) { + if (! ((i + 2) % vc->vc_size_row)) { /* strip trailing blanks from line and add newline, unless non-space at end of line. */ if (obp != bp) { diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index c5c6b5e26850..55971a272ead 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -59,7 +59,7 @@ vcs_size(struct inode *inode) if (!vc_cons_allocated(currcons)) return -ENXIO; - size = video_num_lines * video_num_columns; + size = vc_cons[currcons].d->vc_rows * vc_cons[currcons].d->vc_cols; if (minor & 128) size = 2*size + HEADER_SIZE; @@ -99,6 +99,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; unsigned int currcons = iminor(inode); + struct vc_data *vc; long pos; long viewed, attr, read; int col, maxcol; @@ -126,6 +127,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) ret = -ENXIO; if (!vc_cons_allocated(currcons)) goto unlock_out; + vc = vc_cons[currcons].d; ret = -EINVAL; if (pos < 0) @@ -159,15 +161,15 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) con_buf_start = con_buf0 = con_buf; orig_count = this_round; - maxcol = video_num_columns; + maxcol = vc->vc_cols; if (!attr) { - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); col = p % maxcol; p += maxcol - col; while (this_round-- > 0) { - *con_buf0++ = (vcs_scr_readw(currcons, org++) & 0xff); + *con_buf0++ = (vcs_scr_readw(vc, org++) & 0xff); if (++col == maxcol) { - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); col = 0; p += maxcol; } @@ -176,9 +178,9 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) if (p < HEADER_SIZE) { size_t tmp_count; - con_buf0[0] = (char) video_num_lines; - con_buf0[1] = (char) video_num_columns; - getconsxy(currcons, con_buf0 + 2); + con_buf0[0] = (char)vc->vc_rows; + con_buf0[1] = (char)vc->vc_cols; + getconsxy(vc, con_buf0 + 2); con_buf_start += p; this_round += p; @@ -214,7 +216,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) p /= 2; col = p % maxcol; - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); p += maxcol - col; /* Buffer has even length, so we can always copy @@ -224,10 +226,10 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) this_round = (this_round + 1) >> 1; while (this_round) { - *tmp_buf++ = vcs_scr_readw(currcons, org++); + *tmp_buf++ = vcs_scr_readw(vc, org++); this_round --; if (++col == maxcol) { - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); col = 0; p += maxcol; } @@ -270,6 +272,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; unsigned int currcons = iminor(inode); + struct vc_data *vc; long pos; long viewed, attr, size, written; char *con_buf0; @@ -299,6 +302,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) ret = -ENXIO; if (!vc_cons_allocated(currcons)) goto unlock_out; + vc = vc_cons[currcons].d; size = vcs_size(inode); ret = -EINVAL; @@ -351,10 +355,10 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) con_buf0 = con_buf; orig_count = this_round; - maxcol = video_num_columns; + maxcol = vc->vc_cols; p = pos; if (!attr) { - org0 = org = screen_pos(currcons, p, viewed); + org0 = org = screen_pos(vc, p, viewed); col = p % maxcol; p += maxcol - col; @@ -362,11 +366,11 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) unsigned char c = *con_buf0++; this_round--; - vcs_scr_writew(currcons, - (vcs_scr_readw(currcons, org) & 0xff00) | c, org); + vcs_scr_writew(vc, + (vcs_scr_readw(vc, org) & 0xff00) | c, org); org++; if (++col == maxcol) { - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); col = 0; p += maxcol; } @@ -375,34 +379,34 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) if (p < HEADER_SIZE) { char header[HEADER_SIZE]; - getconsxy(currcons, header + 2); + getconsxy(vc, header + 2); while (p < HEADER_SIZE && this_round > 0) { this_round--; header[p++] = *con_buf0++; } if (!viewed) - putconsxy(currcons, header + 2); + putconsxy(vc, header + 2); } p -= HEADER_SIZE; col = (p/2) % maxcol; if (this_round > 0) { - org0 = org = screen_pos(currcons, p/2, viewed); + org0 = org = screen_pos(vc, p/2, viewed); if ((p & 1) && this_round > 0) { char c; this_round--; c = *con_buf0++; #ifdef __BIG_ENDIAN - vcs_scr_writew(currcons, c | - (vcs_scr_readw(currcons, org) & 0xff00), org); + vcs_scr_writew(vc, c | + (vcs_scr_readw(vc, org) & 0xff00), org); #else - vcs_scr_writew(currcons, (c << 8) | - (vcs_scr_readw(currcons, org) & 0xff), org); + vcs_scr_writew(vc, (c << 8) | + (vcs_scr_readw(vc, org) & 0xff), org); #endif org++; p++; if (++col == maxcol) { - org = screen_pos(currcons, p/2, viewed); + org = screen_pos(vc, p/2, viewed); col = 0; } } @@ -413,11 +417,11 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) unsigned short w; w = get_unaligned(((const unsigned short *)con_buf0)); - vcs_scr_writew(currcons, w, org++); + vcs_scr_writew(vc, w, org++); con_buf0 += 2; this_round -= 2; if (++col == maxcol) { - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); col = 0; p += maxcol; } @@ -427,9 +431,9 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) c = *con_buf0++; #ifdef __BIG_ENDIAN - vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff) | (c << 8), org); + vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff) | (c << 8), org); #else - vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org); + vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff00) | c, org); #endif } } diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 7ef949fbceb5..261599fd095a 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -40,15 +40,6 @@ * - Arno Griffioen * - David Carter * - * Note that the abstract console driver allows all consoles to be of - * potentially different sizes, so the following variables depend on the - * current console (currcons): - * - * - video_num_columns - * - video_num_lines - * - video_size_row - * - can_do_color - * * The abstract console driver provides a generic interface for a text * console. It supports VGA text mode, frame buffer based graphical consoles * and special graphics processors that are only accessible through some @@ -146,13 +137,13 @@ static const struct consw *con_driver_map[MAX_NR_CONSOLES]; static int con_open(struct tty_struct *, struct file *); static void vc_init(unsigned int console, unsigned int rows, unsigned int cols, int do_clear); -static void gotoxy(int currcons, int new_x, int new_y); +static void gotoxy(struct vc_data *vc, int new_x, int new_y); static void save_cur(int currcons); static void reset_terminal(int currcons, int do_clear); static void con_flush_chars(struct tty_struct *tty); static void set_vesa_blanking(char __user *p); -static void set_cursor(int currcons); -static void hide_cursor(int currcons); +static void set_cursor(struct vc_data *vc); +static void hide_cursor(struct vc_data *vc); static void console_callback(void *ignored); static void blank_screen_t(unsigned long dummy); @@ -223,28 +214,32 @@ enum { * Low-Level Functions */ -#define IS_FG (currcons == fg_console) +#define IS_FG (currcons == fg_console) +#define IS_FG_VC(vc) (vc == vc_cons[fg_console].d) + #define IS_VISIBLE CON_IS_VISIBLE(vc_cons[currcons].d) #ifdef VT_BUF_VRAM_ONLY -#define DO_UPDATE 0 +#define DO_UPDATE 0 +#define DO_UPDATE_VC(vc) 0 #else -#define DO_UPDATE IS_VISIBLE +#define DO_UPDATE IS_VISIBLE +#define DO_UPDATE_VC(vc) CON_IS_VISIBLE(vc) #endif static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data); static struct pm_dev *pm_con; -static inline unsigned short *screenpos(int currcons, int offset, int viewed) +static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) { unsigned short *p; if (!viewed) - p = (unsigned short *)(origin + offset); - else if (!sw->con_screen_pos) - p = (unsigned short *)(visible_origin + offset); + p = (unsigned short *)(vc->vc_origin + offset); + else if (!vc->vc_sw->con_screen_pos) + p = (unsigned short *)(vc->vc_visible_origin + offset); else - p = sw->con_screen_pos(vc_cons[currcons].d, offset); + p = vc->vc_sw->con_screen_pos(vc, offset); return p; } @@ -265,14 +260,15 @@ static void scrup(int currcons, unsigned int t, unsigned int b, int nr) if (t+nr >= b) nr = b - t - 1; - if (b > video_num_lines || t >= b || nr < 1) + if (b > vc_cons[currcons].d->vc_rows || t >= b || nr < 1) return; if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr)) return; - d = (unsigned short *) (origin+video_size_row*t); - s = (unsigned short *) (origin+video_size_row*(t+nr)); - scr_memmovew(d, s, (b-t-nr) * video_size_row); - scr_memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr); + d = (unsigned short *) (origin+vc_cons[currcons].d->vc_size_row*t); + s = (unsigned short *) (origin+vc_cons[currcons].d->vc_size_row*(t+nr)); + scr_memmovew(d, s, (b-t-nr) * vc_cons[currcons].d->vc_size_row); + scr_memsetw(d + (b-t-nr) * vc_cons[currcons].d->vc_cols, video_erase_char, + vc_cons[currcons].d->vc_size_row * nr); } static void @@ -283,40 +279,40 @@ scrdown(int currcons, unsigned int t, unsigned int b, int nr) if (t+nr >= b) nr = b - t - 1; - if (b > video_num_lines || t >= b || nr < 1) + if (b > vc_cons[currcons].d->vc_rows || t >= b || nr < 1) return; if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr)) return; - s = (unsigned short *) (origin+video_size_row*t); - step = video_num_columns * nr; - scr_memmovew(s + step, s, (b-t-nr)*video_size_row); + s = (unsigned short *) (origin+vc_cons[currcons].d->vc_size_row*t); + step = vc_cons[currcons].d->vc_cols * nr; + scr_memmovew(s + step, s, (b-t-nr)*vc_cons[currcons].d->vc_size_row); scr_memsetw(s, video_erase_char, 2*step); } -static void do_update_region(int currcons, unsigned long start, int count) +static void do_update_region(struct vc_data *vc, unsigned long start, int count) { #ifndef VT_BUF_VRAM_ONLY unsigned int xx, yy, offset; u16 *p; p = (u16 *) start; - if (!sw->con_getxy) { - offset = (start - origin) / 2; - xx = offset % video_num_columns; - yy = offset / video_num_columns; + if (!vc->vc_sw->con_getxy) { + offset = (start - vc->vc_origin) / 2; + xx = offset % vc->vc_cols; + yy = offset / vc->vc_cols; } else { int nxx, nyy; - start = sw->con_getxy(vc_cons[currcons].d, start, &nxx, &nyy); + start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy); xx = nxx; yy = nyy; } for(;;) { u16 attrib = scr_readw(p) & 0xff00; int startx = xx; u16 *q = p; - while (xx < video_num_columns && count) { + while (xx < vc->vc_cols && count) { if (attrib != (scr_readw(p) & 0xff00)) { if (p > q) - sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx); + vc->vc_sw->con_putcs(vc, q, p-q, yy, startx); startx = xx; q = p; attrib = scr_readw(p) & 0xff00; @@ -326,14 +322,14 @@ static void do_update_region(int currcons, unsigned long start, int count) count--; } if (p > q) - sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx); + vc->vc_sw->con_putcs(vc, q, p-q, yy, startx); if (!count) break; xx = 0; yy++; - if (sw->con_getxy) { + if (vc->vc_sw->con_getxy) { p = (u16 *)start; - start = sw->con_getxy(vc_cons[currcons].d, start, NULL, NULL); + start = vc->vc_sw->con_getxy(vc, start, NULL, NULL); } } #endif @@ -344,9 +340,9 @@ void update_region(int currcons, unsigned long start, int count) WARN_CONSOLE_UNLOCKED(); if (DO_UPDATE) { - hide_cursor(currcons); - do_update_region(currcons, start, count); - set_cursor(currcons); + hide_cursor(vc_cons[currcons].d); + do_update_region(vc_cons[currcons].d, start, count); + set_cursor(vc_cons[currcons].d); } } @@ -370,7 +366,7 @@ static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _unde */ { u8 a = color; - if (!can_do_color) + if (!vc_cons[currcons].d->vc_can_do_color) return _intensity | (_underline ? 4 : 0) | (_reverse ? 8 : 0) | @@ -401,31 +397,30 @@ static void update_attr(int currcons) } /* Note: inverting the screen twice should revert to the original state */ - -void invert_screen(int currcons, int offset, int count, int viewed) +void invert_screen(struct vc_data *vc, int offset, int count, int viewed) { unsigned short *p; WARN_CONSOLE_UNLOCKED(); count /= 2; - p = screenpos(currcons, offset, viewed); - if (sw->con_invert_region) - sw->con_invert_region(vc_cons[currcons].d, p, count); + p = screenpos(vc, offset, viewed); + if (vc->vc_sw->con_invert_region) + vc->vc_sw->con_invert_region(vc, p, count); #ifndef VT_BUF_VRAM_ONLY else { u16 *q = p; int cnt = count; u16 a; - if (!can_do_color) { + if (!vc->vc_can_do_color) { while (cnt--) { a = scr_readw(q); a ^= 0x0800; scr_writew(a, q); q++; } - } else if (hi_font_mask == 0x100) { + } else if (vc->vc_hi_font_mask == 0x100) { while (cnt--) { a = scr_readw(q); a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4); @@ -442,12 +437,12 @@ void invert_screen(int currcons, int offset, int count, int viewed) } } #endif - if (DO_UPDATE) - do_update_region(currcons, (unsigned long) p, count); + if (DO_UPDATE_VC(vc)) + do_update_region(vc, (unsigned long) p, count); } /* used by selection: complement pointer position */ -void complement_pos(int currcons, int offset) +void complement_pos(struct vc_data *vc, int offset) { static unsigned short *p; static unsigned short old; @@ -457,21 +452,21 @@ void complement_pos(int currcons, int offset) if (p) { scr_writew(old, p); - if (DO_UPDATE) - sw->con_putc(vc_cons[currcons].d, old, oldy, oldx); + if (DO_UPDATE_VC(vc)) + vc->vc_sw->con_putc(vc, old, oldy, oldx); } if (offset == -1) p = NULL; else { unsigned short new; - p = screenpos(currcons, offset, 1); + p = screenpos(vc, offset, 1); old = scr_readw(p); - new = old ^ complement_mask; + new = old ^ vc->vc_complement_mask; scr_writew(new, p); - if (DO_UPDATE) { - oldx = (offset >> 1) % video_num_columns; - oldy = (offset >> 1) / video_num_columns; - sw->con_putc(vc_cons[currcons].d, new, oldy, oldx); + if (DO_UPDATE_VC(vc)) { + oldx = (offset >> 1) % vc->vc_cols; + oldy = (offset >> 1) / vc->vc_cols; + vc->vc_sw->con_putc(vc, new, oldy, oldx); } } } @@ -480,7 +475,7 @@ static void insert_char(int currcons, unsigned int nr) { unsigned short *p, *q = (unsigned short *) pos; - p = q + video_num_columns - nr - x; + p = q + vc_cons[currcons].d->vc_cols - nr - x; while (--p >= q) scr_writew(scr_readw(p), p + nr); scr_memsetw(q, video_erase_char, nr*2); @@ -488,7 +483,7 @@ static void insert_char(int currcons, unsigned int nr) if (DO_UPDATE) { unsigned short oldattr = attr; sw->con_bmove(vc_cons[currcons].d,y,x,y,x+nr,1, - video_num_columns-x-nr); + vc_cons[currcons].d->vc_cols-x-nr); attr = video_erase_char >> 8; while (nr--) sw->con_putc(vc_cons[currcons].d, @@ -502,7 +497,7 @@ static void delete_char(int currcons, unsigned int nr) unsigned int i = x; unsigned short *p = (unsigned short *) pos; - while (++i <= video_num_columns - nr) { + while (++i <= vc_cons[currcons].d->vc_cols - nr) { scr_writew(scr_readw(p+nr), p); p++; } @@ -511,22 +506,22 @@ static void delete_char(int currcons, unsigned int nr) if (DO_UPDATE) { unsigned short oldattr = attr; sw->con_bmove(vc_cons[currcons].d, y, x+nr, y, x, 1, - video_num_columns-x-nr); + vc_cons[currcons].d->vc_cols-x-nr); attr = video_erase_char >> 8; while (nr--) sw->con_putc(vc_cons[currcons].d, video_erase_char, y, - video_num_columns-1-nr); + vc_cons[currcons].d->vc_cols-1-nr); attr = oldattr; } } static int softcursor_original; -static void add_softcursor(int currcons) +static void add_softcursor(struct vc_data *vc) { - int i = scr_readw((u16 *) pos); - u32 type = cursor_type; + int i = scr_readw((u16 *) vc->vc_pos); + u32 type = vc->vc_cursor_type; if (! (type & 0x10)) return; if (softcursor_original != -1) return; @@ -535,41 +530,43 @@ static void add_softcursor(int currcons) i ^= ((type) & 0xff00 ); if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000; if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700; - scr_writew(i, (u16 *) pos); - if (DO_UPDATE) - sw->con_putc(vc_cons[currcons].d, i, y, x); + scr_writew(i, (u16 *) vc->vc_pos); + if (DO_UPDATE_VC(vc)) + vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x); } -static void hide_softcursor(int currcons) +static void hide_softcursor(struct vc_data *vc) { if (softcursor_original != -1) { - scr_writew(softcursor_original,(u16 *) pos); - if (DO_UPDATE) - sw->con_putc(vc_cons[currcons].d, softcursor_original, y, x); + scr_writew(softcursor_original, (u16 *)vc->vc_pos); + if (DO_UPDATE_VC(vc)) + vc->vc_sw->con_putc(vc, softcursor_original, + vc->vc_y, vc->vc_x); softcursor_original = -1; } } -static void hide_cursor(int currcons) +static void hide_cursor(struct vc_data *vc) { - if (currcons == sel_cons) + if (vc == sel_cons) clear_selection(); - sw->con_cursor(vc_cons[currcons].d,CM_ERASE); - hide_softcursor(currcons); + vc->vc_sw->con_cursor(vc, CM_ERASE); + hide_softcursor(vc); } -static void set_cursor(int currcons) +static void set_cursor(struct vc_data *vc) { - if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS) - return; - if (deccm) { - if (currcons == sel_cons) - clear_selection(); - add_softcursor(currcons); - if ((cursor_type & 0x0f) != 1) - sw->con_cursor(vc_cons[currcons].d,CM_DRAW); - } else - hide_cursor(currcons); + if (!IS_FG_VC(vc) || console_blanked || + vc->vc_vt->vc_mode == KD_GRAPHICS) + return; + if (vc->vc_deccm) { + if (vc == sel_cons) + clear_selection(); + add_softcursor(vc); + if ((vc->vc_cursor_type & 0x0f) != 1) + vc->vc_sw->con_cursor(vc, CM_DRAW); + } else + hide_cursor(vc); } static void set_origin(int currcons) @@ -582,7 +579,7 @@ static void set_origin(int currcons) origin = (unsigned long) screenbuf; visible_origin = origin; scr_end = origin + screenbuf_size; - pos = origin + video_size_row*y + 2*x; + pos = origin + vc_cons[currcons].d->vc_size_row*y + 2*x; } static inline void save_screen(int currcons) @@ -623,7 +620,7 @@ void redraw_screen(int new_console, int is_switch) if (is_switch) { currcons = fg_console; - hide_cursor(currcons); + hide_cursor(vc_cons[currcons].d); if (fg_console != new_console) { struct vc_data **display = vc_cons[new_console].d->vc_display_fg; old_console = (*display) ? (*display)->vc_num : fg_console; @@ -640,7 +637,7 @@ void redraw_screen(int new_console, int is_switch) } } else { currcons = new_console; - hide_cursor(currcons); + hide_cursor(vc_cons[currcons].d); } if (redraw) { @@ -661,9 +658,9 @@ void redraw_screen(int new_console, int is_switch) clear_buffer_attributes(currcons); } if (update && vcmode != KD_GRAPHICS) - do_update_region(currcons, origin, screenbuf_size/2); + do_update_region(vc_cons[currcons].d, origin, screenbuf_size/2); } - set_cursor(currcons); + set_cursor(vc_cons[currcons].d); if (is_switch) { set_leds(); compute_shiftstate(); @@ -696,13 +693,14 @@ static void visual_init(int currcons, int init) vc_cons[currcons].d->vc_uni_pagedir = 0; hi_font_mask = 0; complement_mask = 0; - can_do_color = 0; + vc_cons[currcons].d->vc_can_do_color = 0; sw->con_init(vc_cons[currcons].d, init); if (!complement_mask) - complement_mask = can_do_color ? 0x7700 : 0x0800; + complement_mask = + vc_cons[currcons].d->vc_can_do_color ? 0x7700 : 0x0800; s_complement_mask = complement_mask; - video_size_row = video_num_columns<<1; - screenbuf_size = video_num_lines*video_size_row; + vc_cons[currcons].d->vc_size_row = vc_cons[currcons].d->vc_cols<<1; + screenbuf_size = vc_cons[currcons].d->vc_rows * vc_cons[currcons].d->vc_size_row; } int vc_allocate(unsigned int currcons) /* return 0 on success */ @@ -730,6 +728,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ memset((void *)p, 0, structsize); vc_cons[currcons].d = (struct vc_data *)p; vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data)); + vc_cons[currcons].d->vc_vt = vt_cons[currcons]; visual_init(currcons, 1); if (!*vc_cons[currcons].d->vc_uni_pagedir_loc) con_set_default_unimap(currcons); @@ -742,7 +741,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ } screenbuf = (unsigned short *) q; kmalloced = 1; - vc_init(currcons, video_num_lines, video_num_columns, 1); + vc_init(currcons, vc_cons[currcons].d->vc_rows, vc_cons[currcons].d->vc_cols, 1); if (!pm_con) { pm_con = pm_register(PM_SYS_DEV, @@ -785,21 +784,21 @@ int vc_resize(int currcons, unsigned int cols, unsigned int lines) if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW) return -EINVAL; - new_cols = (cols ? cols : video_num_columns); - new_rows = (lines ? lines : video_num_lines); + new_cols = (cols ? cols : vc_cons[currcons].d->vc_cols); + new_rows = (lines ? lines : vc_cons[currcons].d->vc_rows); new_row_size = new_cols << 1; new_screen_size = new_row_size * new_rows; - if (new_cols == video_num_columns && new_rows == video_num_lines) + if (new_cols == vc_cons[currcons].d->vc_cols && new_rows == vc_cons[currcons].d->vc_rows) return 0; newscreen = (unsigned short *) kmalloc(new_screen_size, GFP_USER); if (!newscreen) return -ENOMEM; - old_rows = video_num_lines; - old_cols = video_num_columns; - old_row_size = video_size_row; + old_rows = vc_cons[currcons].d->vc_rows; + old_cols = vc_cons[currcons].d->vc_cols; + old_row_size = vc_cons[currcons].d->vc_size_row; old_screen_size = screenbuf_size; err = resize_screen(currcons, new_cols, new_rows); @@ -808,9 +807,9 @@ int vc_resize(int currcons, unsigned int cols, unsigned int lines) return err; } - video_num_lines = new_rows; - video_num_columns = new_cols; - video_size_row = new_row_size; + vc_cons[currcons].d->vc_rows = new_rows; + vc_cons[currcons].d->vc_cols = new_cols; + vc_cons[currcons].d->vc_size_row = new_row_size; screenbuf_size = new_screen_size; rlth = min(old_row_size, new_row_size); @@ -841,16 +840,16 @@ int vc_resize(int currcons, unsigned int cols, unsigned int lines) /* do part of a reset_terminal() */ top = 0; - bottom = video_num_lines; - gotoxy(currcons, x, y); + bottom = vc_cons[currcons].d->vc_rows; + gotoxy(vc_cons[currcons].d, x, y); save_cur(currcons); if (vc_cons[currcons].d->vc_tty) { struct winsize ws, *cws = &vc_cons[currcons].d->vc_tty->winsize; memset(&ws, 0, sizeof(ws)); - ws.ws_row = video_num_lines; - ws.ws_col = video_num_columns; + ws.ws_row = vc_cons[currcons].d->vc_rows; + ws.ws_col = vc_cons[currcons].d->vc_cols; ws.ws_ypixel = video_scan_lines; if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) && vc_cons[currcons].d->vc_tty->pgrp > 0) @@ -913,38 +912,40 @@ int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, * might also be negative. If the given position is out of * bounds, the cursor is placed at the nearest margin. */ -static void gotoxy(int currcons, int new_x, int new_y) +static void gotoxy(struct vc_data *vc, int new_x, int new_y) { int min_y, max_y; if (new_x < 0) - x = 0; - else - if (new_x >= video_num_columns) - x = video_num_columns - 1; + vc->vc_x = 0; + else { + if (new_x >= vc->vc_cols) + vc->vc_x = vc->vc_cols - 1; else - x = new_x; - if (decom) { - min_y = top; - max_y = bottom; + vc->vc_x = new_x; + } + + if (vc->vc_decom) { + min_y = vc->vc_top; + max_y = vc->vc_bottom; } else { min_y = 0; - max_y = video_num_lines; + max_y = vc->vc_rows; } if (new_y < min_y) - y = min_y; + vc->vc_y = min_y; else if (new_y >= max_y) - y = max_y - 1; + vc->vc_y = max_y - 1; else - y = new_y; - pos = origin + y*video_size_row + (x<<1); - need_wrap = 0; + vc->vc_y = new_y; + vc->vc_pos = vc->vc_origin + vc->vc_y * vc->vc_size_row + (vc->vc_x<<1); + vc->vc_need_wrap = 0; } /* for absolute user moves, when decom is set */ static void gotoxay(int currcons, int new_x, int new_y) { - gotoxy(currcons, new_x, decom ? (top+new_y) : new_y); + gotoxy(vc_cons[currcons].d, new_x, decom ? (top+new_y) : new_y); } void scrollback(int lines) @@ -952,7 +953,7 @@ void scrollback(int lines) int currcons = fg_console; if (!lines) - lines = video_num_lines/2; + lines = vc_cons[currcons].d->vc_rows/2; scrolldelta(-lines); } @@ -961,7 +962,7 @@ void scrollfront(int lines) int currcons = fg_console; if (!lines) - lines = video_num_lines/2; + lines = vc_cons[currcons].d->vc_rows/2; scrolldelta(lines); } @@ -972,9 +973,9 @@ static void lf(int currcons) */ if (y+1 == bottom) scrup(currcons,top,bottom,1); - else if (y < video_num_lines-1) { + else if (y < vc_cons[currcons].d->vc_rows-1) { y++; - pos += video_size_row; + pos += vc_cons[currcons].d->vc_size_row; } need_wrap = 0; } @@ -988,7 +989,7 @@ static void ri(int currcons) scrdown(currcons,top,bottom,1); else if (y > 0) { y--; - pos -= video_size_row; + pos -= vc_cons[currcons].d->vc_size_row; } need_wrap = 0; } @@ -1025,10 +1026,10 @@ static void csi_J(int currcons, int vpar) if (DO_UPDATE) { /* do in two stages */ sw->con_clear(vc_cons[currcons].d, y, x, 1, - video_num_columns-x); + vc_cons[currcons].d->vc_cols-x); sw->con_clear(vc_cons[currcons].d, y+1, 0, - video_num_lines-y-1, - video_num_columns); + vc_cons[currcons].d->vc_rows-y-1, + vc_cons[currcons].d->vc_cols); } break; case 1: /* erase from start to cursor */ @@ -1037,18 +1038,18 @@ static void csi_J(int currcons, int vpar) if (DO_UPDATE) { /* do in two stages */ sw->con_clear(vc_cons[currcons].d, 0, 0, y, - video_num_columns); + vc_cons[currcons].d->vc_cols); sw->con_clear(vc_cons[currcons].d, y, 0, 1, x + 1); } break; case 2: /* erase whole display */ - count = video_num_columns * video_num_lines; + count = vc_cons[currcons].d->vc_cols * vc_cons[currcons].d->vc_rows; start = (unsigned short *) origin; if (DO_UPDATE) sw->con_clear(vc_cons[currcons].d, 0, 0, - video_num_lines, - video_num_columns); + vc_cons[currcons].d->vc_rows, + vc_cons[currcons].d->vc_cols); break; default: return; @@ -1064,11 +1065,11 @@ static void csi_K(int currcons, int vpar) switch (vpar) { case 0: /* erase from cursor to end of line */ - count = video_num_columns-x; + count = vc_cons[currcons].d->vc_cols-x; start = (unsigned short *) pos; if (DO_UPDATE) sw->con_clear(vc_cons[currcons].d, y, x, 1, - video_num_columns-x); + vc_cons[currcons].d->vc_cols-x); break; case 1: /* erase from start of line to cursor */ start = (unsigned short *) (pos - (x<<1)); @@ -1079,10 +1080,10 @@ static void csi_K(int currcons, int vpar) break; case 2: /* erase whole line */ start = (unsigned short *) (pos - (x<<1)); - count = video_num_columns; + count = vc_cons[currcons].d->vc_cols; if (DO_UPDATE) sw->con_clear(vc_cons[currcons].d, y, 0, 1, - video_num_columns); + vc_cons[currcons].d->vc_cols); break; default: return; @@ -1097,7 +1098,7 @@ static void csi_X(int currcons, int vpar) /* erase the following vpar positions if (!vpar) vpar++; - count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar; + count = (vpar > vc_cons[currcons].d->vc_cols-x) ? (vc_cons[currcons].d->vc_cols-x) : vpar; scr_memsetw((unsigned short *) pos, video_erase_char, 2 * count); if (DO_UPDATE) @@ -1270,7 +1271,7 @@ static void set_mode(int currcons, int on_off) case 3: /* 80/132 mode switch unimplemented */ deccolm = on_off; #if 0 - (void) vc_resize(deccolm ? 132 : 80, video_num_lines); + (void) vc_resize(deccolm ? 132 : 80, vc_cons[currcons].d->vc_rows); /* this alone does not suffice; some user mode utility has to change the hardware regs */ #endif @@ -1278,7 +1279,7 @@ static void set_mode(int currcons, int on_off) case 5: /* Inverted screen on/off */ if (decscnm != on_off) { decscnm = on_off; - invert_screen(currcons, 0, screenbuf_size, 0); + invert_screen(vc_cons[currcons].d, 0, screenbuf_size, 0); update_attr(currcons); } break; @@ -1325,14 +1326,16 @@ static void setterm_command(int currcons) { switch(par[0]) { case 1: /* set color for underline mode */ - if (can_do_color && par[1] < 16) { + if (vc_cons[currcons].d->vc_can_do_color && + par[1] < 16) { ulcolor = color_table[par[1]]; if (underline) update_attr(currcons); } break; case 2: /* set color for half intensity mode */ - if (can_do_color && par[1] < 16) { + if (vc_cons[currcons].d->vc_can_do_color && + par[1] < 16) { halfcolor = color_table[par[1]]; if (intensity == 0) update_attr(currcons); @@ -1381,8 +1384,8 @@ static void setterm_command(int currcons) /* console_sem is held */ static void csi_at(int currcons, unsigned int nr) { - if (nr > video_num_columns - x) - nr = video_num_columns - x; + if (nr > vc_cons[currcons].d->vc_cols - x) + nr = vc_cons[currcons].d->vc_cols - x; else if (!nr) nr = 1; insert_char(currcons, nr); @@ -1391,8 +1394,8 @@ static void csi_at(int currcons, unsigned int nr) /* console_sem is held */ static void csi_L(int currcons, unsigned int nr) { - if (nr > video_num_lines - y) - nr = video_num_lines - y; + if (nr > vc_cons[currcons].d->vc_rows - y) + nr = vc_cons[currcons].d->vc_rows - y; else if (!nr) nr = 1; scrdown(currcons,y,bottom,nr); @@ -1402,8 +1405,8 @@ static void csi_L(int currcons, unsigned int nr) /* console_sem is held */ static void csi_P(int currcons, unsigned int nr) { - if (nr > video_num_columns - x) - nr = video_num_columns - x; + if (nr > vc_cons[currcons].d->vc_cols - x) + nr = vc_cons[currcons].d->vc_cols - x; else if (!nr) nr = 1; delete_char(currcons, nr); @@ -1412,8 +1415,8 @@ static void csi_P(int currcons, unsigned int nr) /* console_sem is held */ static void csi_M(int currcons, unsigned int nr) { - if (nr > video_num_lines - y) - nr = video_num_lines - y; + if (nr > vc_cons[currcons].d->vc_rows - y) + nr = vc_cons[currcons].d->vc_rows - y; else if (!nr) nr=1; scrup(currcons,y,bottom,nr); @@ -1438,7 +1441,7 @@ static void save_cur(int currcons) /* console_sem is held */ static void restore_cur(int currcons) { - gotoxy(currcons,saved_x,saved_y); + gotoxy(vc_cons[currcons].d,saved_x,saved_y); intensity = s_intensity; underline = s_underline; blink = s_blink; @@ -1460,7 +1463,7 @@ enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, static void reset_terminal(int currcons, int do_clear) { top = 0; - bottom = video_num_lines; + bottom = vc_cons[currcons].d->vc_rows; vc_state = ESnormal; ques = 0; translate = set_translate(LAT1_MAP,currcons); @@ -1507,7 +1510,7 @@ static void reset_terminal(int currcons, int do_clear) bell_pitch = DEFAULT_BELL_PITCH; bell_duration = DEFAULT_BELL_DURATION; - gotoxy(currcons,0,0); + gotoxy(vc_cons[currcons].d, 0, 0); save_cur(currcons); if (do_clear) csi_J(currcons,2); @@ -1532,7 +1535,7 @@ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c) return; case 9: pos -= (x << 1); - while (x < video_num_columns - 1) { + while (x < vc_cons[currcons].d->vc_cols - 1) { x++; if (tab_stop[x >> 5] & (1 << (x & 31))) break; @@ -1719,31 +1722,31 @@ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c) switch(c) { case 'G': case '`': if (par[0]) par[0]--; - gotoxy(currcons,par[0],y); + gotoxy(vc_cons[currcons].d, par[0], y); return; case 'A': if (!par[0]) par[0]++; - gotoxy(currcons,x,y-par[0]); + gotoxy(vc_cons[currcons].d, x, y-par[0]); return; case 'B': case 'e': if (!par[0]) par[0]++; - gotoxy(currcons,x,y+par[0]); + gotoxy(vc_cons[currcons].d, x, y+par[0]); return; case 'C': case 'a': if (!par[0]) par[0]++; - gotoxy(currcons,x+par[0],y); + gotoxy(vc_cons[currcons].d, x+par[0], y); return; case 'D': if (!par[0]) par[0]++; - gotoxy(currcons,x-par[0],y); + gotoxy(vc_cons[currcons].d, x-par[0], y); return; case 'E': if (!par[0]) par[0]++; - gotoxy(currcons,0,y+par[0]); + gotoxy(vc_cons[currcons].d, 0, y+par[0]); return; case 'F': if (!par[0]) par[0]++; - gotoxy(currcons,0,y-par[0]); + gotoxy(vc_cons[currcons].d, 0, y-par[0]); return; case 'd': if (par[0]) par[0]--; @@ -1797,10 +1800,10 @@ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c) if (!par[0]) par[0]++; if (!par[1]) - par[1] = video_num_lines; + par[1] = vc_cons[currcons].d->vc_rows; /* Minimum allowed region is 2 lines */ if (par[0] < par[1] && - par[1] <= video_num_lines) { + par[1] <= vc_cons[currcons].d->vc_rows) { top=par[0]-1; bottom=par[1]; gotoxay(currcons,0,0); @@ -1847,7 +1850,7 @@ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c) csi_J(currcons, 2); video_erase_char = (video_erase_char & 0xff00) | ' '; - do_update_region(currcons, origin, screenbuf_size/2); + do_update_region(vc_cons[currcons].d, origin, screenbuf_size/2); } return; case ESsetG0: @@ -1963,7 +1966,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co /* undraw cursor first */ if (IS_FG) - hide_cursor(currcons); + hide_cursor(vc_cons[currcons].d); while (!tty->stopped && count) { int orig = *buf; @@ -2065,7 +2068,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co draw_x = x; draw_from = pos; } - if (x == video_num_columns - 1) { + if (x == vc_cons[currcons].d->vc_cols - 1) { need_wrap = decawm; draw_to = pos+2; } else { @@ -2102,7 +2105,7 @@ static void console_callback(void *ignored) if (want_console >= 0) { if (want_console != fg_console && vc_cons_allocated(want_console)) { - hide_cursor(fg_console); + hide_cursor(vc_cons[fg_console].d); change_console(want_console); /* we only changed when the console had already been allocated - a new console is not created @@ -2176,7 +2179,7 @@ void vt_console_print(struct console *co, const char *b, unsigned count) /* undraw cursor first */ if (IS_FG) - hide_cursor(currcons); + hide_cursor(vc_cons[currcons].d); start = (ushort *)pos; @@ -2209,7 +2212,7 @@ void vt_console_print(struct console *co, const char *b, unsigned count) } scr_writew((attr << 8) + c, (unsigned short *) pos); cnt++; - if (myx == video_num_columns - 1) { + if (myx == vc_cons[currcons].d->vc_cols - 1) { need_wrap = 1; continue; } @@ -2220,12 +2223,12 @@ void vt_console_print(struct console *co, const char *b, unsigned count) if (IS_VISIBLE) sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x); x += cnt; - if (x == video_num_columns) { + if (x == vc_cons[currcons].d->vc_cols) { x--; need_wrap = 1; } } - set_cursor(currcons); + set_cursor(vc_cons[currcons].d); if (!oops_in_progress) poke_blanked_console(); @@ -2438,7 +2441,7 @@ static void con_flush_chars(struct tty_struct *tty) acquire_console_sem(); vt = tty->driver_data; if (vt) - set_cursor(vt->vc_num); + set_cursor(vc_cons[vt->vc_num].d); release_console_sem(); } @@ -2459,8 +2462,8 @@ static int con_open(struct tty_struct *tty, struct file *filp) vc_cons[currcons].d->vc_tty = tty; if (!tty->winsize.ws_row && !tty->winsize.ws_col) { - tty->winsize.ws_row = video_num_lines; - tty->winsize.ws_col = video_num_columns; + tty->winsize.ws_row = vc_cons[currcons].d->vc_rows; + tty->winsize.ws_col = vc_cons[currcons].d->vc_cols; } release_console_sem(); vcs_make_devfs(tty); @@ -2507,10 +2510,10 @@ static void vc_init(unsigned int currcons, unsigned int rows, { int j, k ; - video_num_columns = cols; - video_num_lines = rows; - video_size_row = cols<<1; - screenbuf_size = video_num_lines * video_size_row; + vc_cons[currcons].d->vc_cols = cols; + vc_cons[currcons].d->vc_rows = rows; + vc_cons[currcons].d->vc_size_row = cols<<1; + screenbuf_size = vc_cons[currcons].d->vc_rows * vc_cons[currcons].d->vc_size_row; set_origin(currcons); pos = origin; @@ -2563,22 +2566,23 @@ static int __init con_init(void) alloc_bootmem(sizeof(struct vc_data)); vt_cons[currcons] = (struct vt_struct *) alloc_bootmem(sizeof(struct vt_struct)); + vc_cons[currcons].d->vc_vt = vt_cons[currcons]; visual_init(currcons, 1); screenbuf = (unsigned short *) alloc_bootmem(screenbuf_size); kmalloced = 0; - vc_init(currcons, video_num_lines, video_num_columns, + vc_init(currcons, vc_cons[currcons].d->vc_rows, vc_cons[currcons].d->vc_cols, currcons || !sw->con_save_screen); } currcons = fg_console = 0; master_display_fg = vc_cons[currcons].d; set_origin(currcons); save_screen(currcons); - gotoxy(currcons,x,y); + gotoxy(vc_cons[currcons].d, x, y); csi_J(currcons, 0); update_screen(fg_console); printk("Console: %s %s %dx%d", - can_do_color ? "colour" : "mono", - display_desc, video_num_columns, video_num_lines); + vc_cons[currcons].d->vc_can_do_color ? "colour" : "mono", + display_desc, vc_cons[currcons].d->vc_cols, vc_cons[currcons].d->vc_rows); printable = 1; printk("\n"); @@ -2690,7 +2694,7 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt) origin = (unsigned long) screenbuf; visible_origin = origin; scr_end = origin + screenbuf_size; - pos = origin + video_size_row*y + 2*x; + pos = origin + vc_cons[currcons].d->vc_size_row*y + 2*x; visual_init(i, 0); update_attr(i); @@ -2788,7 +2792,7 @@ void do_blank_screen(int entering_gfx) /* entering graphics mode? */ if (entering_gfx) { - hide_cursor(currcons); + hide_cursor(vc_cons[currcons].d); save_screen(currcons); sw->con_blank(vc_cons[currcons].d, -1, 1); console_blanked = fg_console + 1; @@ -2802,7 +2806,7 @@ void do_blank_screen(int entering_gfx) return; } - hide_cursor(currcons); + hide_cursor(vc_cons[currcons].d); del_timer_sync(&console_timer); blank_timer_expired = 0; @@ -2859,7 +2863,7 @@ void do_unblank_screen(int leaving_gfx) if (console_blank_hook) console_blank_hook(0); set_palette(currcons); - set_cursor(fg_console); + set_cursor(vc_cons[fg_console].d); } EXPORT_SYMBOL(do_unblank_screen); @@ -3185,47 +3189,47 @@ int con_font_op(int currcons, struct console_font_op *op) */ /* used by selection */ -u16 screen_glyph(int currcons, int offset) +u16 screen_glyph(struct vc_data *vc, int offset) { - u16 w = scr_readw(screenpos(currcons, offset, 1)); + u16 w = scr_readw(screenpos(vc, offset, 1)); u16 c = w & 0xff; - if (w & hi_font_mask) + if (w & vc->vc_hi_font_mask) c |= 0x100; return c; } /* used by vcs - note the word offset */ -unsigned short *screen_pos(int currcons, int w_offset, int viewed) +unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed) { - return screenpos(currcons, 2 * w_offset, viewed); + return screenpos(vc, 2 * w_offset, viewed); } -void getconsxy(int currcons, unsigned char *p) +void getconsxy(struct vc_data *vc, unsigned char *p) { - p[0] = x; - p[1] = y; + p[0] = vc->vc_x; + p[1] = vc->vc_y; } -void putconsxy(int currcons, unsigned char *p) +void putconsxy(struct vc_data *vc, unsigned char *p) { - gotoxy(currcons, p[0], p[1]); - set_cursor(currcons); + gotoxy(vc, p[0], p[1]); + set_cursor(vc); } -u16 vcs_scr_readw(int currcons, const u16 *org) +u16 vcs_scr_readw(struct vc_data *vc, const u16 *org) { - if ((unsigned long)org == pos && softcursor_original != -1) + if ((unsigned long)org == vc->vc_pos && softcursor_original != -1) return softcursor_original; return scr_readw(org); } -void vcs_scr_writew(int currcons, u16 val, u16 *org) +void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org) { scr_writew(val, org); - if ((unsigned long)org == pos) { + if ((unsigned long)org == vc->vc_pos) { softcursor_original = -1; - add_softcursor(currcons); + add_softcursor(vc); } } diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index dd8e2f7817f5..ad3a5d3d394c 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -37,7 +37,7 @@ char vt_dont_switch; extern struct tty_driver *console_driver; #define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count) -#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || i == sel_cons) +#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons) /* * Console (vt and kd) routines, as defined by USL SVR4 manual, and by diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index a9a2a486234c..062049ca5c44 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -9,6 +9,8 @@ * to achieve effects such as fast scrolling by changing the origin. */ +struct vt_struct; + #define NPAR 16 struct vc_data { @@ -87,6 +89,7 @@ struct vc_data { struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */ unsigned long vc_uni_pagedir; unsigned long *vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */ + struct vt_struct *vc_vt; /* additional information is in vt_kern.h */ }; diff --git a/include/linux/selection.h b/include/linux/selection.h index 059c958951f3..ed3408b400f1 100644 --- a/include/linux/selection.h +++ b/include/linux/selection.h @@ -10,7 +10,7 @@ #include #include -extern int sel_cons; +extern struct vc_data *sel_cons; extern void clear_selection(void); extern int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty); @@ -19,11 +19,6 @@ extern int sel_loadlut(char __user *p); extern int mouse_reporting(void); extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry); -#define video_num_columns (vc_cons[currcons].d->vc_cols) -#define video_num_lines (vc_cons[currcons].d->vc_rows) -#define video_size_row (vc_cons[currcons].d->vc_size_row) -#define can_do_color (vc_cons[currcons].d->vc_can_do_color) - extern int console_blanked; extern unsigned char color_table[]; @@ -31,15 +26,15 @@ extern int default_red[]; extern int default_grn[]; extern int default_blu[]; -extern unsigned short *screen_pos(int currcons, int w_offset, int viewed); -extern u16 screen_glyph(int currcons, int offset); -extern void complement_pos(int currcons, int offset); -extern void invert_screen(int currcons, int offset, int count, int shift); +extern unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed); +extern u16 screen_glyph(struct vc_data *vc, int offset); +extern void complement_pos(struct vc_data *vc, int offset); +extern void invert_screen(struct vc_data *vc, int offset, int count, int shift); -extern void getconsxy(int currcons, unsigned char *p); -extern void putconsxy(int currcons, unsigned char *p); +extern void getconsxy(struct vc_data *vc, unsigned char *p); +extern void putconsxy(struct vc_data *vc, unsigned char *p); -extern u16 vcs_scr_readw(int currcons, const u16 *org); -extern void vcs_scr_writew(int currcons, u16 val, u16 *org); +extern u16 vcs_scr_readw(struct vc_data *vc, const u16 *org); +extern void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org); #endif -- cgit v1.2.3 From f5dbb2b796763f47bd81ccf7e12f26e67243e7d1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 10 Jan 2005 17:20:52 -0800 Subject: [PATCH] warn about cli, sti & co uses even on UP These don't exist on SMP at all, at least warn on compiling for UP. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/interrupt.h | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 991831cff1da..d99e7aeb7d33 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -61,12 +61,30 @@ extern void enable_irq(unsigned int irq); * Temporary defines for UP kernels, until all code gets fixed. */ #ifndef CONFIG_SMP -# define cli() local_irq_disable() -# define sti() local_irq_enable() -# define save_flags(x) local_save_flags(x) -# define restore_flags(x) local_irq_restore(x) -# define save_and_cli(x) local_irq_save(x) -#endif +static inline void __deprecated cli(void) +{ + local_irq_disable(); +} +static inline void __deprecated sti(void) +{ + local_irq_enable(); +} +static inline void __deprecated save_flags(unsigned long *x) +{ + local_save_flags(*x); +} +#define save_flags(x) save_flags(&x); +static inline void __deprecated restore_flags(unsigned long x) +{ + local_irq_restore(x); +} + +static inline void __deprecated save_and_cli(unsigned long *x) +{ + local_irq_save(*x); +} +#define save_and_cli(x) save_and_cli(&x) +#endif /* CONFIG_SMP */ /* SoftIRQ primitives. */ #define local_bh_disable() \ -- cgit v1.2.3 From 9f6142d7d1f6fbe7c240e1a6fe067feef570634b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 10 Jan 2005 17:21:11 -0800 Subject: [PATCH] remove umsdos from tree UMSDOS has been non-function since early 2.5 and would need a major rewrite to be resurrected (which I don't hope anyone plans as it's a really horrible hack) From: Adrian Bunk With umsdos gone, there's no longer a MAINTAINERS entry required. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/00-INDEX | 2 - Documentation/filesystems/umsdos.txt | 100 --- MAINTAINERS | 7 - fs/Kconfig | 46 +- fs/Makefile | 1 - fs/umsdos/Makefile | 13 - fs/umsdos/README-WIP.txt | 114 ---- fs/umsdos/dir.c | 810 ------------------------ fs/umsdos/emd.c | 660 -------------------- fs/umsdos/inode.c | 483 --------------- fs/umsdos/ioctl.c | 446 -------------- fs/umsdos/mangle.c | 522 ---------------- fs/umsdos/namei.c | 1124 ---------------------------------- fs/umsdos/rdir.c | 248 -------- fs/umsdos/specs | 289 --------- include/linux/umsdos_fs.h | 182 ------ include/linux/umsdos_fs.p | 100 --- include/linux/umsdos_fs_i.h | 58 -- 18 files changed, 2 insertions(+), 5203 deletions(-) delete mode 100644 Documentation/filesystems/umsdos.txt delete mode 100644 fs/umsdos/Makefile delete mode 100644 fs/umsdos/README-WIP.txt delete mode 100644 fs/umsdos/dir.c delete mode 100644 fs/umsdos/emd.c delete mode 100644 fs/umsdos/inode.c delete mode 100644 fs/umsdos/ioctl.c delete mode 100644 fs/umsdos/mangle.c delete mode 100644 fs/umsdos/namei.c delete mode 100644 fs/umsdos/rdir.c delete mode 100644 fs/umsdos/specs delete mode 100644 include/linux/umsdos_fs.h delete mode 100644 include/linux/umsdos_fs.p delete mode 100644 include/linux/umsdos_fs_i.h (limited to 'include/linux') diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX index 6cf8082f605b..bcfbab899b37 100644 --- a/Documentation/filesystems/00-INDEX +++ b/Documentation/filesystems/00-INDEX @@ -42,8 +42,6 @@ udf.txt - info and mount options for the UDF filesystem. ufs.txt - info on the ufs filesystem. -umsdos.txt - - info on the umsdos extensions to the msdos filesystem. vfat.txt - info on using the VFAT filesystem used in Windows NT and Windows 95 vfs.txt diff --git a/Documentation/filesystems/umsdos.txt b/Documentation/filesystems/umsdos.txt deleted file mode 100644 index c253708f3466..000000000000 --- a/Documentation/filesystems/umsdos.txt +++ /dev/null @@ -1,100 +0,0 @@ -Firstly, let me say that UMSDOS is going through some major code changes, -and has some KNOWN BUGS (and quite a few unknown :-). Please read -fs/umsdos/README-WIP.txt for more information on current status. Thanks. - ----------------------------------------------------------------------------- -Very short explanation for the impatient! - -Umsdos is a file system driver that run on top the MSDOS fs driver. -It is written by Jacques Gelinas (jacques@solucorp.qc.ca) -and is currently maintained by Matija Nalis (mnalis@jagor.srce.hr) - -Umsdos is not a file system per se, but a twist to make a boring -one into a useful one. - -It gives you: - - long file names - Permissions and owners - Links - Special files (devices, pipes...) - All that is needed to be a linux root fs. - -There is plenty of documentation on it in the source. A formatted document -made from those comments is available from -sunsite.unc.edu:/pub/Linux/system/Filesystems/umsdos. - -You mount a DOS partition like this: - -mount -t umsdos /dev/hda3 /mnt - ^ ----------| - -All options are passed to the msdos drivers. Option like uid,gid etc are -given to msdos. - -The default behavior of Umsdos is to do the same thing as the msdos driver -mostly passing commands to it without much processing. Again, this is -the default. After doing the mount on a DOS partition, nothing special -happens. This is why all mount options are passed to the msdos fs driver. - -Umsdos uses a special DOS file --linux-.--- to store the information -which can't be handled by the normal MS-DOS filesystem. This is the trick. - ---linux-.--- is optional. There is one per directory. - -**** If --linux-.--- is missing, then Umsdos process the directory the - same way the msdos driver does. Short file names, no goodies, default - owner and permissions. So each directory may have or not this - --linux-.--- - -Now, how to get those --linux-.---. - -\begin joke_section - - Well send me a directory content - and I will send you one customised for you. - $5 per directory. Add any applicable taxes. -\end joke_section - -A utility umssync creates those. The kernel maintains them. It is available -from the same directory above (sunsite) in the file umsdos_progs-0.7.tar.gz. -A compiled version is available in umsdos_progs-0.7.bin.tar.gz. - -So in our example, after mounting mnt, we do - - umssync . - -This will promote this directory (a recursive option is available) to full -umsdos capabilities (long name, etc.). However, an "ls -l" before and after -won't show much difference. The files which were there are still there, but -now you can do all this: - - chmod 644 * - chown you.your_group * - ls >THIS_IS.A.VERY.LONG.NAME - ln -s toto tata - ls -l - -Once a directory is promoted, all subdirectories created will inherit that -promotion. - -What happens if you boot DOS and create files in those promoted directories ? -Umsdos won't notice new files, but will signal removed files (it won't crash). -Using umssync in /etc/rc will make sure the DOS directory is in sync with -the --linux-.---. - -It is a good idea to put the following command in your RC file just -after the "mount -a": - - mount -a - /sbin/umssync -i+ -c+ -r99 /umsdos_mount_point - - (You put one for each umsdos mount point in the fstab) - -This will ensure nice operation. A umsdos.fsck is in the making, -so you will be allowed to manage umsdos partitions in the same way -other filesystems are, using the generic fsck front end. - -Hope this helps! - diff --git a/MAINTAINERS b/MAINTAINERS index df0d9e0b30e4..502b6bf95c5e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2244,13 +2244,6 @@ L: linux_udf@hpesjro.fc.hp.com W: http://linux-udf.sourceforge.net S: Maintained -UMSDOS FILESYSTEM -P: Matija Nalis -M: Matija Nalis -L: linux-kernel@vger.kernel.org -W: http://linux.voyager.hr/umsdos/ -S: Maintained - UNIFORM CDROM DRIVER P: Jens Axboe M: axboe@suse.de diff --git a/fs/Kconfig b/fs/Kconfig index e2661f504c5d..17e4eb1b97a8 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -578,9 +578,8 @@ config FAT_FS tristate select NLS help - If you want to use one of the FAT-based file systems (the MS-DOS, - VFAT (Windows 95) and UMSDOS (used to run Linux on top of an - ordinary DOS partition) file systems), then you must say Y or M here + If you want to use one of the FAT-based file systems (the MS-DOS and + VFAT (Windows 95) file systems), then you must say Y or M here to include FAT support. You will then be able to mount partitions or diskettes with FAT-based file systems and transparently access the files on them, i.e. MSDOS files will look and behave just like all @@ -612,9 +611,6 @@ config FAT_FS fat. Note that if you compile the FAT support as a module, you cannot compile any of the FAT-based file systems into the kernel -- they will have to be modules as well. - The file system of your root partition (the one containing the - directory /) cannot be a module, so don't say M here if you intend - to use UMSDOS as your root file system. config MSDOS_FS tristate "MSDOS fs support" @@ -631,10 +627,6 @@ config MSDOS_FS transparent, i.e. the MSDOS files look and behave just like all other Unix files. - If you want to use UMSDOS, the Unix-like file system on top of a - DOS file system, which allows you to run Linux from within a DOS - partition without repartitioning, you'll have to say Y or M here. - If you have Windows 95 or Windows NT installed on your MSDOS partitions, you should use the VFAT file system (say Y to "VFAT fs support" below), or you will not be able to see the long filenames @@ -654,11 +646,6 @@ config VFAT_FS used by Windows 95, Windows 98, Windows NT 4.0, and the Unix programs from the mtools package. - You cannot use the VFAT file system for your Linux root partition - (the one containing the directory /); use UMSDOS instead if you - want to run Linux from within a DOS partition (i.e. say Y to - "Unix like fs on top of std MSDOS fs", below). - The VFAT support enlarges your kernel by about 10 KB and it only works if you said Y to the "DOS FAT fs support" above. Please read the file for details. If @@ -689,35 +676,6 @@ config FAT_DEFAULT_IOCHARSET If unsure, you shouldn't set "utf8" here. See for more information. -config UMSDOS_FS -#dep_tristate ' UMSDOS: Unix-like file system on top of standard MSDOS fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS -# UMSDOS is temprory broken - bool - help - Say Y here if you want to run Linux from within an existing DOS - partition of your hard drive. The advantage of this is that you can - get away without repartitioning your hard drive (which often implies - backing everything up and restoring afterwards) and hence you're - able to quickly try out Linux or show it to your friends; the - disadvantage is that Linux becomes susceptible to DOS viruses and - that UMSDOS is somewhat slower than ext2fs. Another use of UMSDOS - is to write files with long unix filenames to MSDOS floppies; it - also allows Unix-style soft-links and owner/permissions of files on - MSDOS floppies. You will need a program called umssync in order to - make use of UMSDOS; read - . - - To get utilities for initializing/checking UMSDOS file system, or - latest patches and/or information, visit the UMSDOS home page at - . - - This option enlarges your kernel by about 28 KB and it only works if - you said Y to both "DOS FAT fs support" and "MSDOS fs support" - above. To compile this as a module, choose M here: the module will be - called umsdos. Note that the file system of your root partition - (the one containing the directory /) cannot be a module, so saying M - could be dangerous. If unsure, say N. - config NTFS_FS tristate "NTFS file system support" select NLS diff --git a/fs/Makefile b/fs/Makefile index 82dbf96892fa..443f2bc56ccf 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -57,7 +57,6 @@ obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ obj-$(CONFIG_CODA_FS) += coda/ obj-$(CONFIG_MINIX_FS) += minix/ obj-$(CONFIG_FAT_FS) += fat/ -obj-$(CONFIG_UMSDOS_FS) += umsdos/ obj-$(CONFIG_MSDOS_FS) += msdos/ obj-$(CONFIG_VFAT_FS) += vfat/ obj-$(CONFIG_BFS_FS) += bfs/ diff --git a/fs/umsdos/Makefile b/fs/umsdos/Makefile deleted file mode 100644 index 7de26124539a..000000000000 --- a/fs/umsdos/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# -# Makefile for the umsdos Unix-like filesystem routines. -# - -obj-$(CONFIG_UMSDOS) += umsdos.o - -umsdos-objs := dir.o inode.o ioctl.o mangle.o namei.o rdir.o emd.o - -p: - proto *.c >/usr/include/linux/umsdos_fs.p - -doc: - nadoc -i -p umsdos.doc - /tmp/umsdos.mpg diff --git a/fs/umsdos/README-WIP.txt b/fs/umsdos/README-WIP.txt deleted file mode 100644 index 14643c738f6e..000000000000 --- a/fs/umsdos/README-WIP.txt +++ /dev/null @@ -1,114 +0,0 @@ -Changes by Matija Nalis (mnalis@jagor.srce.hr) on umsdos dentry fixing -(started by Peter T. Waltenberg ) -(Final conversion to dentries Bill Hawes ) - -There is no warning any more. -Both read-only and read-write stuff is fixed, both in -msdos-compatibile mode, and in umsdos EMD mode, and it seems stable. - -Userland NOTE: new umsdos_progs (umssync, umssetup, udosctl & friends) that -will compile and work on 2.2.x+ kernels and glibc based systems, as well as -kernel patches and other umsdos related information may be found at -http://linux.voyager.hr/umsdos/ - -Information below is getting outdated slowly -- I'll fix it one day when I -get enough time - there are more important things to fix right now. - -Legend: those lines marked with '+' on the beggining of line indicates it -passed all of my tests, and performed perfect in all of them. - -Current status (010125) - UMSDOS 0.86j: - -(1) pure MSDOS (no --linux-.--- EMD file): - -READ: -+ readdir - works -+ lookup - works -+ read file - works - -WRITE: -+ creat file - works -+ unlink file - works -+ write file - works -+ rename file (same dir) - works -+ rename file (dif. dir) - works -+ rename dir (same dir) - works -+ rename dir (dif. dir) - works -+ mkdir - works -+ rmdir - works - - -(2) umsdos (with --linux-.--- EMD file): - -READ: -+ readdir - works -+ lookup - works -+ permissions/owners stuff - works -+ long file names - works -+ read file - works -+ switching MSDOS/UMSDOS - works -+ switching UMSDOS/MSDOS - works -- pseudo root things - works mostly. See notes below. -+ resolve symlink - works -+ dereference symlink - works -+ dangling symlink - works -+ hard links - works -+ special files (block/char devices, FIFOs, sockets...) - works -+ various umsdos ioctls - works - - -WRITE: -+ create symlink - works -+ create hardlink - works -+ create file - works -+ create special file - works -+ write to file - works -+ rename file (same dir) - works -+ rename file (dif. dir) - works -+ rename hardlink (same dir) - works -- rename hardlink (dif. dir) - works, but see notes below. -+ rename symlink (same dir) - works -+ rename symlink (dif. dir) - works -+ rename dir (same dir) - works -+ rename dir (dif. dir) - works -+ unlink file - works -+ notify_change (chown,perms) - works -+ notify_change for hardlinks - works -+ unlink hardlink - works -+ mkdir - works -+ rmdir - works -+ umssyncing (many ioctls) - works - - -- CVF-FAT stuff (compressed DOS filesystem) - there is some support from Frank - Gockel to use it even under umsdosfs, but I - have no way of testing it -- please let me know if there are problems specific - to umsdos (for instance, it works under msdosfs, but not under umsdosfs). - - -Some current notes: - -Note: creating and using pseudo-hardlinks is always non-perfect, especially -in filesystems that might be externally modified like umsdos. There is -example is specs file about it. Specifically, moving directory which -contains hardlinks will break them. - -Note: (about creating hardlinks in pseudoroot mode) - hardlinks created in -pseudoroot mode are now again compatibile with 'normal' hardlinks, and vice -versa. Thanks to Sorin Iordachescu for providing fix. -See http://linux.voyager.hr/umsdos/hlbug.html for more info and upgrade -procedure if you used broken versions... - ------------------------------------------------------------------------------- - -Some general notes: - -Good idea when running development kernels is to have SysRq support compiled -in kernel, and use Sync/Emergency-remount-RO if you bump into problems (like -not being able to umount(2) umsdosfs, and because of it root partition also, -or panics which force you to reboot etc.) - -I'm unfortunately somewhat out of time to read linux-kernel@vger, but I do -check for messages having "UMSDOS" in the subject, and read them. I might -miss some in all that volume, though. I should reply to any direct e-mail -in few days. If I don't, probably I never got your message. diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c deleted file mode 100644 index 775f02021128..000000000000 --- a/fs/umsdos/dir.c +++ /dev/null @@ -1,810 +0,0 @@ -/* - * linux/fs/umsdos/dir.c - * - * Written 1993 by Jacques Gelinas - * Inspired from linux/fs/msdos/... : Werner Almesberger - * - * Extended MS-DOS directory handling functions - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define UMSDOS_SPECIAL_DIRFPOS 3 -extern struct dentry *saved_root; -extern struct inode *pseudo_root; - -/* #define UMSDOS_DEBUG_VERBOSE 1 */ - -/* - * Dentry operations routines - */ - -/* nothing for now ... */ -static int umsdos_dentry_validate(struct dentry *dentry, struct nameidata *nd) -{ - return 1; -} - -/* for now, drop everything to force lookups ... */ -/* ITYM s/everything/& positive/... */ -static int umsdos_dentry_dput(struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - if (inode) { - return 1; - } - return 0; -} - -struct dentry_operations umsdos_dentry_operations = -{ - .d_revalidate = umsdos_dentry_validate, - .d_delete = umsdos_dentry_dput, -}; - -struct UMSDOS_DIR_ONCE { - void *dirbuf; - filldir_t filldir; - int count; - int stop; -}; - -/* - * Record a single entry the first call. - * Return -EINVAL the next one. - * NOTE: filldir DOES NOT use a dentry - */ - -static int umsdos_dir_once ( void *buf, - const char *name, - int len, - loff_t offset, - ino_t ino, - unsigned type) -{ - int ret = -EINVAL; - struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf; - - if (d->count == 0) { - PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n", - len, name, offset)); - ret = d->filldir (d->dirbuf, name, len, offset, ino, DT_UNKNOWN); - d->stop = ret < 0; - d->count = 1; - } - return ret; -} - - -/* - * Read count directory entries from directory filp - * Return a negative value from linux/errno.h. - * Return > 0 if success (the number of bytes written by filldir). - * - * This function is used by the normal readdir VFS entry point, - * and in order to get the directory entry from a file's dentry. - * See umsdos_dentry_to_entry() below. - */ - -static int umsdos_readdir_x (struct inode *dir, struct file *filp, - void *dirbuf, struct umsdos_dirent *u_entry, - filldir_t filldir) -{ - struct dentry *demd; - off_t start_fpos; - int ret = 0; - loff_t pos; - - umsdos_startlookup (dir); - - if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS && dir == pseudo_root) { - - /* - * We don't need to simulate this pseudo directory - * when umsdos_readdir_x is called for internal operation - * of umsdos. This is why dirent_in_fs is tested - */ - /* #Specification: pseudo root / directory /DOS - * When umsdos operates in pseudo root mode (C:\linux is the - * linux root), it simulate a directory /DOS which points to - * the real root of the file system. - */ - - Printk ((KERN_WARNING "umsdos_readdir_x: pseudo_root thing UMSDOS_SPECIAL_DIRFPOS\n")); - if (filldir (dirbuf, "DOS", 3, - UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO, DT_DIR) == 0) { - filp->f_pos++; - } - goto out_end; - } - - if (filp->f_pos < 2 || - (dir->i_ino != UMSDOS_ROOT_INO && filp->f_pos == 32)) { - - int last_f_pos = filp->f_pos; - struct UMSDOS_DIR_ONCE bufk; - - Printk (("umsdos_readdir_x: . or .. /mn/?\n")); - - bufk.dirbuf = dirbuf; - bufk.filldir = filldir; - bufk.count = 0; - - ret = fat_readdir (filp, &bufk, umsdos_dir_once); - if (last_f_pos > 0 && filp->f_pos > last_f_pos) - filp->f_pos = UMSDOS_SPECIAL_DIRFPOS; - if (u_entry != NULL) - u_entry->flags = 0; - goto out_end; - } - - Printk (("umsdos_readdir_x: normal file /mn/?\n")); - - /* get the EMD dentry */ - demd = umsdos_get_emd_dentry(filp->f_dentry); - ret = PTR_ERR(demd); - if (IS_ERR(demd)) - goto out_end; - ret = -EIO; - if (!demd->d_inode) { - printk(KERN_WARNING - "umsdos_readir_x: EMD file %s/%s not found\n", - demd->d_parent->d_name.name, demd->d_name.name); - goto out_dput; - } - - pos = filp->f_pos; - start_fpos = filp->f_pos; - - if (pos <= UMSDOS_SPECIAL_DIRFPOS + 1) - pos = 0; - ret = 0; - while (pos < demd->d_inode->i_size) { - off_t cur_f_pos = pos; - struct dentry *dret; - struct inode *inode; - struct umsdos_dirent entry; - struct umsdos_info info; - - ret = -EIO; - if (umsdos_emd_dir_readentry (demd, &pos, &entry) != 0) - break; - if (entry.name_len == 0) - continue; -#ifdef UMSDOS_DEBUG_VERBOSE -if (entry.flags & UMSDOS_HLINK) -printk("umsdos_readdir_x: %s/%s is hardlink\n", -filp->f_dentry->d_name.name, entry.name); -#endif - - umsdos_parse (entry.name, entry.name_len, &info); - info.f_pos = cur_f_pos; - umsdos_manglename (&info); - /* - * Do a real lookup on the short name. - */ - dret = umsdos_covered(filp->f_dentry, info.fake.fname, - info.fake.len); - ret = PTR_ERR(dret); - if (IS_ERR(dret)) - break; - /* - * If the file wasn't found, remove it from the EMD. - */ - inode = dret->d_inode; - if (!inode) - goto remove_name; -#ifdef UMSDOS_DEBUG_VERBOSE -if (UMSDOS_I(inode)->i_is_hlink) -printk("umsdos_readdir_x: %s/%s already resolved, ino=%ld\n", -dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino); -#endif - -Printk (("Found %s/%s, ino=%ld, flags=%x\n", -dret->d_parent->d_name.name, info.fake.fname, dret->d_inode->i_ino, -entry.flags)); - /* check whether to resolve a hard-link */ - if ((entry.flags & UMSDOS_HLINK) && - !UMSDOS_I(inode)->i_is_hlink) { - dret = umsdos_solve_hlink (dret); - ret = PTR_ERR(dret); - if (IS_ERR(dret)) - break; - inode = dret->d_inode; - if (!inode) { -printk("umsdos_readdir_x: %s/%s negative after link\n", -dret->d_parent->d_name.name, dret->d_name.name); - goto clean_up; - } - } - - /* #Specification: pseudo root / reading real root - * The pseudo root (/linux) is logically - * erased from the real root. This means that - * ls /DOS, won't show "linux". This avoids - * infinite recursion (/DOS/linux/DOS/linux/...) while - * walking the file system. - */ - if (inode != pseudo_root && !(entry.flags & UMSDOS_HIDDEN)) { - if (filldir (dirbuf, entry.name, entry.name_len, - cur_f_pos, inode->i_ino, DT_UNKNOWN) < 0) { - pos = cur_f_pos; - } -Printk(("umsdos_readdir_x: got %s/%s, ino=%ld\n", -dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino)); - if (u_entry != NULL) - *u_entry = entry; - dput(dret); - ret = 0; - break; - } - clean_up: - dput(dret); - continue; - - remove_name: - /* #Specification: umsdos / readdir / not in MSDOS - * During a readdir operation, if the file is not - * in the MS-DOS directory any more, the entry is - * removed from the EMD file silently. - */ -#ifdef UMSDOS_PARANOIA -printk("umsdos_readdir_x: %s/%s out of sync, erasing\n", -filp->f_dentry->d_name.name, info.entry.name); -#endif - ret = umsdos_delentry(filp->f_dentry, &info, - S_ISDIR(info.entry.mode)); - if (ret) - printk(KERN_WARNING - "umsdos_readdir_x: delentry %s, err=%d\n", - info.entry.name, ret); - goto clean_up; - } - /* - * If the fillbuf has failed, f_pos is back to 0. - * To avoid getting back into the . and .. state - * (see comments at the beginning), we put back - * the special offset. - */ - filp->f_pos = pos; - if (filp->f_pos == 0) - filp->f_pos = start_fpos; -out_dput: - dput(demd); - -out_end: - umsdos_endlookup (dir); - - Printk ((KERN_DEBUG "read dir %p pos %Ld ret %d\n", - dir, filp->f_pos, ret)); - return ret; -} - - -/* - * Read count directory entries from directory filp. - * Return a negative value from linux/errno.h. - * Return 0 or positive if successful. - */ - -static int UMSDOS_readdir (struct file *filp, void *dirbuf, filldir_t filldir) -{ - struct inode *dir = filp->f_dentry->d_inode; - int ret = 0, count = 0; - struct UMSDOS_DIR_ONCE bufk; - - lock_kernel(); - - bufk.dirbuf = dirbuf; - bufk.filldir = filldir; - bufk.stop = 0; - - Printk (("UMSDOS_readdir in\n")); - while (ret == 0 && bufk.stop == 0) { - struct umsdos_dirent entry; - - bufk.count = 0; - ret = umsdos_readdir_x (dir, filp, &bufk, &entry, - umsdos_dir_once); - if (bufk.count == 0) - break; - count += bufk.count; - } - unlock_kernel(); - Printk (("UMSDOS_readdir out %d count %d pos %Ld\n", - ret, count, filp->f_pos)); - return count ? : ret; -} - - -/* - * Complete the inode content with info from the EMD file. - * - * This function modifies the state of a dir inode. It decides - * whether the dir is a UMSDOS or DOS directory. This is done - * deeper in umsdos_patch_inode() called at the end of this function. - * - * Because it is does disk access, umsdos_patch_inode() may block. - * At the same time, another process may get here to initialise - * the same directory inode. There are three cases. - * - * 1) The inode is already initialised. We do nothing. - * 2) The inode is not initialised. We lock access and do it. - * 3) Like 2 but another process has locked the inode, so we try - * to lock it and check right afterward check whether - * initialisation is still needed. - * - * - * Thanks to the "mem" option of the kernel command line, it was - * possible to consistently reproduce this problem by limiting - * my memory to 4 MB and running X. - * - * Do this only if the inode is freshly read, because we will lose - * the current (updated) content. - * - * A lookup of a mount point directory yield the inode into - * the other fs, so we don't care about initialising it. iget() - * does this automatically. - */ - -void umsdos_lookup_patch_new(struct dentry *dentry, struct umsdos_info *info) -{ - struct inode *inode = dentry->d_inode; - struct umsdos_dirent *entry = &info->entry; - - /* - * This part of the initialization depends only on i_patched. - */ - if (UMSDOS_I(inode)->i_patched) - goto out; - UMSDOS_I(inode)->i_patched = 1; - if (S_ISREG (entry->mode)) - entry->mtime = inode->i_mtime; - inode->i_mode = entry->mode; - inode->i_rdev = to_kdev_t (entry->rdev); - inode->i_atime = entry->atime; - inode->i_ctime = entry->ctime; - inode->i_mtime = entry->mtime; - inode->i_uid = entry->uid; - inode->i_gid = entry->gid; - - /* #Specification: umsdos / i_nlink - * The nlink field of an inode is maintained by the MSDOS file system - * for directory and by UMSDOS for other files. The logic is that - * MSDOS is already figuring out what to do for directories and - * does nothing for other files. For MSDOS, there are no hard links - * so all file carry nlink==1. UMSDOS use some info in the - * EMD file to plug the correct value. - */ - if (!S_ISDIR (entry->mode)) { - if (entry->nlink > 0) { - inode->i_nlink = entry->nlink; - } else { - printk (KERN_ERR - "UMSDOS: lookup_patch entry->nlink < 1 ???\n"); - } - } - /* - * The mode may have changed, so patch the inode again. - */ - umsdos_patch_dentry_inode(dentry, info->f_pos); - umsdos_set_dirinfo_new(dentry, info->f_pos); - -out: - return; -} - - -/* - * Return != 0 if an entry is the pseudo DOS entry in the pseudo root. - */ - -int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry) -{ - /* #Specification: pseudo root / DOS hard coded - * The pseudo sub-directory DOS in the pseudo root is hard coded. - * The name is DOS. This is done this way to help standardised - * the umsdos layout. The idea is that from now on /DOS is - * a reserved path and nobody will think of using such a path - * for a package. - */ - return dir == pseudo_root - && dentry->d_name.len == 3 - && dentry->d_name.name[0] == 'D' - && dentry->d_name.name[1] == 'O' - && dentry->d_name.name[2] == 'S'; -} - - -/* - * Check whether a file exists in the current directory. - * Return 0 if OK, negative error code if not (ex: -ENOENT). - * - * fills dentry->d_inode with found inode, and increments its count. - * if not found, return -ENOENT. - */ -/* #Specification: umsdos / lookup - * A lookup for a file is done in two steps. First, we - * locate the file in the EMD file. If not present, we - * return an error code (-ENOENT). If it is there, we - * repeat the operation on the msdos file system. If - * this fails, it means that the file system is not in - * sync with the EMD file. We silently remove this - * entry from the EMD file, and return ENOENT. - */ - -struct dentry *umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo) -{ - struct dentry *dret = NULL; - struct inode *inode; - int ret = -ENOENT; - struct umsdos_info info; - -#ifdef UMSDOS_DEBUG_VERBOSE -printk("umsdos_lookup_x: looking for %s/%s\n", -dentry->d_parent->d_name.name, dentry->d_name.name); -#endif - - umsdos_startlookup (dir); - if (umsdos_is_pseudodos (dir, dentry)) { - /* #Specification: pseudo root / lookup(DOS) - * A lookup of DOS in the pseudo root will always succeed - * and return the inode of the real root. - */ - Printk ((KERN_DEBUG "umsdos_lookup_x: following /DOS\n")); - inode = saved_root->d_inode; - goto out_add; - } - - ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); - if (ret) { -printk("umsdos_lookup_x: %s/%s parse failed, ret=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, ret); - goto out; - } - - ret = umsdos_findentry (dentry->d_parent, &info, 0); - if (ret) { -if (ret != -ENOENT) -printk("umsdos_lookup_x: %s/%s findentry failed, ret=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, ret); - goto out; - } -Printk (("lookup %.*s pos %lu ret %d len %d ", -info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len)); - - /* do a real lookup to get the short name ... */ - dret = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len); - ret = PTR_ERR(dret); - if (IS_ERR(dret)) { -printk("umsdos_lookup_x: %s/%s real lookup failed, ret=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, ret); - goto out; - } - inode = dret->d_inode; - if (!inode) - goto out_remove; - umsdos_lookup_patch_new(dret, &info); -#ifdef UMSDOS_DEBUG_VERBOSE -printk("umsdos_lookup_x: found %s/%s, ino=%ld\n", -dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino); -#endif - - /* Check for a hard link */ - if ((info.entry.flags & UMSDOS_HLINK) && - !UMSDOS_I(inode)->i_is_hlink) { - dret = umsdos_solve_hlink (dret); - ret = PTR_ERR(dret); - if (IS_ERR(dret)) - goto out; - ret = -ENOENT; - inode = dret->d_inode; - if (!inode) { -printk("umsdos_lookup_x: %s/%s negative after link\n", -dret->d_parent->d_name.name, dret->d_name.name); - goto out_dput; - } - } - - if (inode == pseudo_root && !nopseudo) { - /* #Specification: pseudo root / dir lookup - * For the same reason as readdir, a lookup in /DOS for - * the pseudo root directory (linux) will fail. - */ - /* - * This has to be allowed for resolving hard links - * which are recorded independently of the pseudo-root - * mode. - */ -printk("umsdos_lookup_x: skipping DOS/linux\n"); - ret = -ENOENT; - goto out_dput; - } - - /* - * We've found it OK. Now hash the dentry with the inode. - */ -out_add: - atomic_inc(&inode->i_count); - d_add (dentry, inode); - dentry->d_op = &umsdos_dentry_operations; - ret = 0; - -out_dput: - if (dret && dret != dentry) - d_drop(dret); - dput(dret); -out: - umsdos_endlookup (dir); - return ERR_PTR(ret); - -out_remove: - printk(KERN_WARNING "UMSDOS: entry %s/%s out of sync, erased\n", - dentry->d_parent->d_name.name, dentry->d_name.name); - umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode)); - ret = -ENOENT; - goto out_dput; -} - - -/* - * Check whether a file exists in the current directory. - * Return 0 if OK, negative error code if not (ex: -ENOENT). - * - * Called by VFS; should fill dentry->d_inode via d_add. - */ - -struct dentry *UMSDOS_lookup (struct inode *dir, struct dentry *dentry, struct nameidata *nd) -{ - struct dentry *ret; - - ret = umsdos_lookup_x (dir, dentry, 0); - - /* Create negative dentry if not found. */ - if (ret == ERR_PTR(-ENOENT)) { - Printk ((KERN_DEBUG - "UMSDOS_lookup: converting -ENOENT to negative\n")); - d_add (dentry, NULL); - dentry->d_op = &umsdos_dentry_operations; - ret = NULL; - } - return ret; -} - -struct dentry *umsdos_covered(struct dentry *parent, char *name, int len) -{ - struct dentry *result, *dentry; - struct qstr qstr; - - qstr.name = name; - qstr.len = len; - qstr.hash = full_name_hash(name, len); - result = ERR_PTR(-ENOMEM); - dentry = d_alloc(parent, &qstr); - if (dentry) { - /* XXXXXXXXXXXXXXXXXXX Race alert! */ - result = UMSDOS_rlookup(parent->d_inode, dentry); - d_drop(dentry); - if (result) - goto out_fail; - return dentry; - } -out: - return result; - -out_fail: - dput(dentry); - goto out; -} - -/* - * Lookup or create a dentry from within the filesystem. - * - * We need to use this instead of lookup_dentry, as the - * directory semaphore lock is already held. - */ -struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len, - int real) -{ - struct dentry *result, *dentry; - struct qstr qstr; - - qstr.name = name; - qstr.len = len; - qstr.hash = full_name_hash(name, len); - result = d_lookup(parent, &qstr); - if (!result) { - result = ERR_PTR(-ENOMEM); - dentry = d_alloc(parent, &qstr); - if (dentry) { - result = real ? - UMSDOS_rlookup(parent->d_inode, dentry) : - UMSDOS_lookup(parent->d_inode, dentry); - if (result) - goto out_fail; - return dentry; - } - } -out: - return result; - -out_fail: - dput(dentry); - goto out; -} - -/* - * Return a path relative to our root. - */ -char * umsdos_d_path(struct dentry *dentry, char * buffer, int len) -{ - struct dentry * old_root; - char * path; - - read_lock(¤t->fs->lock); - old_root = dget(current->fs->root); - read_unlock(¤t->fs->lock); - spin_lock(&dcache_lock); - path = __d_path(dentry, current->fs->rootmnt, dentry->d_sb->s_root, current->fs->rootmnt, buffer, len); /* FIXME: current->fs->rootmnt */ - spin_unlock(&dcache_lock); - - if (*path == '/') - path++; /* skip leading '/' */ - - if (current->fs->root->d_inode == pseudo_root) - { - *(path-1) = '/'; - path -= (UMSDOS_PSDROOT_LEN+1); - memcpy(path, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN); - } - dput(old_root); - - return path; -} - -/* - * Return the dentry which points to a pseudo-hardlink. - * - * it should try to find file it points to - * if file is found, return new dentry/inode - * The resolved inode will have i_is_hlink set. - * - * Note: the original dentry is always dput(), even if an error occurs. - */ - -struct dentry *umsdos_solve_hlink (struct dentry *hlink) -{ - /* root is our root for resolving pseudo-hardlink */ - struct dentry *base = hlink->d_sb->s_root; - struct dentry *dentry_dst; - char *path, *pt; - int len; - struct address_space *mapping = hlink->d_inode->i_mapping; - struct page *page; - - page=read_cache_page(mapping,0,(filler_t *)mapping->a_ops->readpage,NULL); - dentry_dst=(struct dentry *)page; - if (IS_ERR(page)) - goto out; - wait_on_page_locked(page); - if (!PageUptodate(page)) - goto async_fail; - - dentry_dst = ERR_PTR(-ENOMEM); - path = (char *) kmalloc (PATH_MAX, GFP_KERNEL); - if (path == NULL) - goto out_release; - memcpy(path, kmap(page), hlink->d_inode->i_size); - kunmap(page); - page_cache_release(page); - - len = hlink->d_inode->i_size; - - /* start at root dentry */ - dentry_dst = dget(base); - path[len] = '\0'; - - pt = path; - if (*path == '/') - pt++; /* skip leading '/' */ - - if (base->d_inode == pseudo_root) - pt += (UMSDOS_PSDROOT_LEN + 1); - - while (1) { - struct dentry *dir = dentry_dst, *demd; - char *start = pt; - int real; - - while (*pt != '\0' && *pt != '/') pt++; - len = (int) (pt - start); - if (*pt == '/') *pt++ = '\0'; - - real = 1; - demd = umsdos_get_emd_dentry(dir); - if (!IS_ERR(demd)) { - if (demd->d_inode) - real = 0; - dput(demd); - } - -#ifdef UMSDOS_DEBUG_VERBOSE -printk ("umsdos_solve_hlink: dir %s/%s, name=%s, real=%d\n", -dir->d_parent->d_name.name, dir->d_name.name, start, real); -#endif - dentry_dst = umsdos_lookup_dentry(dir, start, len, real); -/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ - if (real) - d_drop(dir); - dput (dir); - if (IS_ERR(dentry_dst)) - break; - /* not found? stop search ... */ - if (!dentry_dst->d_inode) { - break; - } - if (*pt == '\0') /* we're finished! */ - break; - } /* end while */ - - if (!IS_ERR(dentry_dst)) { - struct inode *inode = dentry_dst->d_inode; - if (inode) { - UMSDOS_I(inode)->i_is_hlink = 1; -#ifdef UMSDOS_DEBUG_VERBOSE -printk ("umsdos_solve_hlink: resolved link %s/%s, ino=%ld\n", -dentry_dst->d_parent->d_name.name, dentry_dst->d_name.name, inode->i_ino); -#endif - } else { -#ifdef UMSDOS_DEBUG_VERBOSE -printk ("umsdos_solve_hlink: resolved link %s/%s negative!\n", -dentry_dst->d_parent->d_name.name, dentry_dst->d_name.name); -#endif - } - } else - printk(KERN_WARNING - "umsdos_solve_hlink: err=%ld\n", PTR_ERR(dentry_dst)); - kfree (path); - -out: - dput(hlink); /* original hlink no longer needed */ - return dentry_dst; - -async_fail: - dentry_dst = ERR_PTR(-EIO); -out_release: - page_cache_release(page); - goto out; -} - - -struct file_operations umsdos_dir_operations = -{ - .read = generic_read_dir, - .readdir = UMSDOS_readdir, - .ioctl = UMSDOS_ioctl_dir, -}; - -struct inode_operations umsdos_dir_inode_operations = -{ - .create = UMSDOS_create, - .lookup = UMSDOS_lookup, - .link = UMSDOS_link, - .unlink = UMSDOS_unlink, - .symlink = UMSDOS_symlink, - .mkdir = UMSDOS_mkdir, - .rmdir = UMSDOS_rmdir, - .mknod = UMSDOS_mknod, - .rename = UMSDOS_rename, - .setattr = UMSDOS_notify_change, -}; diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c deleted file mode 100644 index 16a15d75dcd7..000000000000 --- a/fs/umsdos/emd.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * linux/fs/umsdos/emd.c - * - * Written 1993 by Jacques Gelinas - * - * Extended MS-DOS directory handling functions - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void put_entry (struct umsdos_dirent *p, struct umsdos_dirent *q) -{ - p->name_len = q->name_len; - p->flags = q->flags; - p->nlink = cpu_to_le16(q->nlink); - p->uid = cpu_to_le16(q->uid); - p->gid = cpu_to_le16(q->gid); - p->atime = cpu_to_le32(q->atime); - p->mtime = cpu_to_le32(q->mtime); - p->ctime = cpu_to_le32(q->ctime); - p->rdev = cpu_to_le16(q->rdev); - p->mode = cpu_to_le16(q->mode); -} - -static void get_entry(struct umsdos_dirent *p, struct umsdos_dirent *q) -{ - p->name_len = q->name_len; - p->name[p->name_len]='\0'; - p->flags = q->flags; - p->nlink = le16_to_cpu (q->nlink); - /* FIXME -- 32bit UID/GID issues */ - p->uid = le16_to_cpu (q->uid); - p->gid = le16_to_cpu (q->gid); - p->atime = le32_to_cpu (q->atime); - p->mtime = le32_to_cpu (q->mtime); - p->ctime = le32_to_cpu (q->ctime); - p->rdev = le16_to_cpu (q->rdev); - p->mode = le16_to_cpu (q->mode); -} - -/* - * Lookup the EMD dentry for a directory. - * - * Note: the caller must hold a lock on the parent directory. - */ -struct dentry *umsdos_get_emd_dentry(struct dentry *parent) -{ - struct dentry *demd; - - demd = umsdos_lookup_dentry(parent, UMSDOS_EMD_FILE, - UMSDOS_EMD_NAMELEN, 1); - return demd; -} - -/* - * Check whether a directory has an EMD file. - * - * Note: the caller must hold a lock on the parent directory. - */ -int umsdos_have_emd(struct dentry *dir) -{ - struct dentry *demd = umsdos_get_emd_dentry (dir); - int found = 0; - - if (!IS_ERR(demd)) { - if (demd->d_inode) - found = 1; - dput(demd); - } - return found; -} - -/* - * Create the EMD file for a directory if it doesn't - * already exist. Returns 0 or an error code. - * - * Note: the caller must hold a lock on the parent directory. - */ -int umsdos_make_emd(struct dentry *parent) -{ - struct dentry *demd = umsdos_get_emd_dentry(parent); - int err = PTR_ERR(demd); - - if (IS_ERR(demd)) { - printk("umsdos_make_emd: can't get dentry in %s, err=%d\n", - parent->d_name.name, err); - goto out; - } - - /* already created? */ - err = 0; - if (demd->d_inode) - goto out_set; - -Printk(("umsdos_make_emd: creating EMD %s/%s\n", -parent->d_name.name, demd->d_name.name)); - - err = msdos_create(parent->d_inode, demd, S_IFREG | 0777, NULL); - if (err) { - printk (KERN_WARNING - "umsdos_make_emd: create %s/%s failed, err=%d\n", - parent->d_name.name, demd->d_name.name, err); - } -out_set: - dput(demd); -out: - return err; -} - - -/* - * Read an entry from the EMD file. - * Support variable length record. - * Return -EIO if error, 0 if OK. - * - * does not change {d,i}_count - */ - -int umsdos_emd_dir_readentry (struct dentry *demd, loff_t *pos, struct umsdos_dirent *entry) -{ - struct address_space *mapping = demd->d_inode->i_mapping; - struct page *page; - struct umsdos_dirent *p; - int offs = *pos & ~PAGE_CACHE_MASK; - int recsize; - int ret = 0; - - page = read_cache_page(mapping, *pos>>PAGE_CACHE_SHIFT, - (filler_t*)mapping->a_ops->readpage, NULL); - if (IS_ERR(page)) - goto sync_fail; - wait_on_page_locked(page); - if (!PageUptodate(page)) - goto async_fail; - p = (struct umsdos_dirent*)(kmap(page)+offs); - - /* if this is an invalid entry (invalid name length), ignore it */ - if( p->name_len > UMSDOS_MAXNAME ) - { - printk (KERN_WARNING "Ignoring invalid EMD entry with size %d\n", entry->name_len); - p->name_len = 0; - ret = -ENAMETOOLONG; /* notify umssync(8) code that something is wrong */ - /* FIXME: does not work if we did 'ls -l' before 'udosctl uls' ?! */ - } - - recsize = umsdos_evalrecsize(p->name_len); - if (offs + recsize > PAGE_CACHE_SIZE) { - struct page *page2; - int part = (char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare; - page2 = read_cache_page(mapping, 1+(*pos>>PAGE_CACHE_SHIFT), - (filler_t*)mapping->a_ops->readpage, NULL); - if (IS_ERR(page2)) { - kunmap(page); - page_cache_release(page); - page = page2; - goto sync_fail; - } - wait_on_page_locked(page2); - if (!PageUptodate(page2)) { - kunmap(page); - page_cache_release(page2); - goto async_fail; - } - memcpy(entry->spare,p->spare,part); - memcpy(entry->spare+part,kmap(page2), - recsize+offs-PAGE_CACHE_SIZE); - kunmap(page2); - page_cache_release(page2); - } else - memcpy(entry->spare,p->spare,((char*)p+recsize)-p->spare); - get_entry(entry, p); - kunmap(page); - page_cache_release(page); - *pos += recsize; - return ret; -async_fail: - page_cache_release(page); - page = ERR_PTR(-EIO); -sync_fail: - return PTR_ERR(page); -} - - -/* - * Write an entry in the EMD file. - * Return 0 if OK, -EIO if some error. - * - * Note: the caller must hold a lock on the parent directory. - */ -int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info, - int free_entry) -{ - struct inode *dir = parent->d_inode; - struct umsdos_dirent *entry = &info->entry; - struct dentry *emd_dentry; - int ret; - struct umsdos_dirent entry0,*p; - struct address_space *mapping; - struct page *page, *page2 = NULL; - int offs; - - emd_dentry = umsdos_get_emd_dentry(parent); - ret = PTR_ERR(emd_dentry); - if (IS_ERR(emd_dentry)) - goto out; - /* make sure there's an EMD file */ - ret = -EIO; - if (!emd_dentry->d_inode) { - printk(KERN_WARNING - "umsdos_writeentry: no EMD file in %s/%s\n", - parent->d_parent->d_name.name, parent->d_name.name); - goto out_dput; - } - - if (free_entry) { - /* #Specification: EMD file / empty entries - * Unused entries in the EMD file are identified - * by the name_len field equal to 0. However to - * help future extension (or bug correction :-( ), - * empty entries are filled with 0. - */ - memset (&entry0, 0, sizeof (entry0)); - entry = &entry0; - } else if (entry->name_len > 0) { - memset (entry->name + entry->name_len, '\0', - sizeof (entry->name) - entry->name_len); - /* #Specification: EMD file / spare bytes - * 10 bytes are unused in each record of the EMD. They - * are set to 0 all the time, so it will be possible - * to do new stuff and rely on the state of those - * bytes in old EMD files. - */ - memset (entry->spare, 0, sizeof (entry->spare)); - } - - /* write the entry and update the parent timestamps */ - mapping = emd_dentry->d_inode->i_mapping; - offs = info->f_pos & ~PAGE_CACHE_MASK; - ret = -ENOMEM; - page = grab_cache_page(mapping, info->f_pos>>PAGE_CACHE_SHIFT); - if (!page) - goto out_dput; - p = (struct umsdos_dirent *) (page_address(page) + offs); - if (offs + info->recsize > PAGE_CACHE_SIZE) { - ret = mapping->a_ops->prepare_write(NULL,page,offs, - PAGE_CACHE_SIZE); - if (ret) - goto out_unlock; - page2 = grab_cache_page(mapping, - (info->f_pos>>PAGE_CACHE_SHIFT)+1); - if (!page2) - goto out_unlock2; - ret = mapping->a_ops->prepare_write(NULL,page2,0, - offs+info->recsize-PAGE_CACHE_SIZE); - if (ret) - goto out_unlock3; - put_entry (p, entry); - memcpy(p->spare,entry->spare, - (char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare); - memcpy(page_address(page2), - ((char*)entry)+PAGE_CACHE_SIZE-offs, - offs+info->recsize-PAGE_CACHE_SIZE); - ret = mapping->a_ops->commit_write(NULL,page2,0, - offs+info->recsize-PAGE_CACHE_SIZE); - if (ret) - goto out_unlock3; - ret = mapping->a_ops->commit_write(NULL,page,offs, - PAGE_CACHE_SIZE); - unlock_page(page2); - page_cache_release(page2); - if (ret) - goto out_unlock; - } else { - ret = mapping->a_ops->prepare_write(NULL,page,offs, - offs + info->recsize); - if (ret) - goto out_unlock; - put_entry (p, entry); - memcpy(p->spare,entry->spare,((char*)p+info->recsize)-p->spare); - ret = mapping->a_ops->commit_write(NULL,page,offs, - offs + info->recsize); - if (ret) - goto out_unlock; - } - unlock_page(page); - page_cache_release(page); - - dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; - mark_inode_dirty(dir); - -out_dput: - dput(emd_dentry); -out: - Printk (("umsdos_writeentry /mn/: returning %d...\n", ret)); - return ret; -out_unlock3: - unlock_page(page2); - page_cache_release(page2); -out_unlock2: - ClearPageUptodate(page); - kunmap(page); -out_unlock: - unlock_page(page); - page_cache_release(page); - printk ("UMSDOS: problem with EMD file: can't write\n"); - goto out_dput; -} - -/* - * General search, locate a name in the EMD file or an empty slot to - * store it. if info->entry.name_len == 0, search the first empty - * slot (of the proper size). - * - * Return 0 if found, -ENOENT if not found, another error code if - * other problem. - * - * So this routine is used to either find an existing entry or to - * create a new one, while making sure it is a new one. After you - * get -ENOENT, you make sure the entry is stuffed correctly and - * call umsdos_writeentry(). - * - * To delete an entry, you find it, zero out the entry (memset) - * and call umsdos_writeentry(). - * - * All this to say that umsdos_writeentry must be called after this - * function since it relies on the f_pos field of info. - * - * Note: the caller must hold a lock on the parent directory. - */ -/* #Specification: EMD file structure - * The EMD file uses a fairly simple layout. It is made of records - * (UMSDOS_REC_SIZE == 64). When a name can't be written in a single - * record, multiple contiguous records are allocated. - */ - -static int umsdos_find (struct dentry *demd, struct umsdos_info *info) -{ - struct umsdos_dirent *entry = &info->entry; - int recsize = info->recsize; - struct inode *emd_dir; - int ret = -ENOENT; - struct { - off_t posok; /* Position available to store the entry */ - off_t one; /* One empty position -> maybe <- large enough */ - } empty; - int found = 0; - int empty_size = 0; - struct address_space *mapping; - filler_t *readpage; - struct page *page = NULL; - int index = -1; - int offs = PAGE_CACHE_SIZE,max_offs = PAGE_CACHE_SIZE; - char *p = NULL; - loff_t pos = 0; - - /* make sure there's an EMD file ... */ - ret = -ENOENT; - emd_dir = demd->d_inode; - if (!emd_dir) - goto out_dput; - mapping = emd_dir->i_mapping; - readpage = (filler_t*)mapping->a_ops->readpage; - - empty.posok = emd_dir->i_size; - while (1) { - struct umsdos_dirent *rentry; - int entry_size; - - if (offs >= max_offs) { - if (page) { - kunmap(page); - page_cache_release(page); - page = NULL; - } - if (pos >= emd_dir->i_size) { - info->f_pos = empty.posok; - break; - } - if (++index == (emd_dir->i_size>>PAGE_CACHE_SHIFT)) - max_offs = emd_dir->i_size & ~PAGE_CACHE_MASK; - offs -= PAGE_CACHE_SIZE; - page = read_cache_page(mapping,index,readpage,NULL); - if (IS_ERR(page)) - goto sync_fail; - wait_on_page_locked(page); - if (!PageUptodate(page)) - goto async_fail; - p = kmap(page); - } - - rentry = (struct umsdos_dirent *)(p+offs); - - if (rentry->name_len == 0) { - /* We are looking for an empty section at least */ - /* as large as recsize. */ - if (entry->name_len == 0) { - info->f_pos = pos; - ret = 0; - break; - } - offs += UMSDOS_REC_SIZE; - pos += UMSDOS_REC_SIZE; - if (found) - continue; - if (!empty_size) - empty.one = pos-UMSDOS_REC_SIZE; - empty_size += UMSDOS_REC_SIZE; - if (empty_size == recsize) { - /* Here is a large enough section. */ - empty.posok = empty.one; - found = 1; - } - continue; - } - - entry_size = umsdos_evalrecsize(rentry->name_len); - if (entry_size > PAGE_CACHE_SIZE) - goto async_fail; - empty_size = 0; - if (entry->name_len != rentry->name_len) - goto skip_it; - - if (entry_size + offs > PAGE_CACHE_SIZE) { - /* Sucker spans the page boundary */ - int len = (p+PAGE_CACHE_SIZE)-rentry->name; - struct page *next_page; - char *q; - next_page = read_cache_page(mapping,index+1,readpage,NULL); - if (IS_ERR(next_page)) { - page_cache_release(page); - page = next_page; - goto sync_fail; - } - wait_on_page_locked(next_page); - if (!PageUptodate(next_page)) { - page_cache_release(page); - page = next_page; - goto async_fail; - } - q = kmap(next_page); - if (memcmp(entry->name, rentry->name, len) || - memcmp(entry->name+len, q, entry->name_len-len)) { - kunmap(next_page); - page_cache_release(next_page); - goto skip_it; - } - kunmap(next_page); - page_cache_release(next_page); - } else if (memcmp (entry->name, rentry->name, entry->name_len)) - goto skip_it; - - info->f_pos = pos; - get_entry(entry, rentry); - ret = 0; - break; -skip_it: - offs+=entry_size; - pos+=entry_size; - } - if (page) { - kunmap(page); - page_cache_release(page); - } - umsdos_manglename (info); - -out_dput: - dput(demd); - return ret; - -async_fail: - page_cache_release(page); - page = ERR_PTR(-EIO); -sync_fail: - return PTR_ERR(page); -} - - -/* - * Add a new entry in the EMD file. - * Return 0 if OK or a negative error code. - * Return -EEXIST if the entry already exists. - * - * Complete the information missing in info. - * - * N.B. What if the EMD file doesn't exist? - */ - -int umsdos_newentry (struct dentry *parent, struct umsdos_info *info) -{ - int err, ret = -EEXIST; - struct dentry *demd = umsdos_get_emd_dentry(parent); - - ret = PTR_ERR(demd); - if (IS_ERR(demd)) - goto out; - err = umsdos_find (demd, info); - if (err && err == -ENOENT) { - ret = umsdos_writeentry (parent, info, 0); - Printk (("umsdos_writeentry EMD ret = %d\n", ret)); - } -out: - return ret; -} - - -/* - * Create a new hidden link. - * Return 0 if OK, an error code if not. - */ - -/* #Specification: hard link / hidden name - * When a hard link is created, the original file is renamed - * to a hidden name. The name is "..LINKNNN" where NNN is a - * number define from the entry offset in the EMD file. - */ -int umsdos_newhidden (struct dentry *parent, struct umsdos_info *info) -{ - int ret; - struct dentry *demd = umsdos_get_emd_dentry(parent); - ret = PTR_ERR(demd); - if (IS_ERR(demd)) - goto out; - - umsdos_parse ("..LINK", 6, info); - info->entry.name_len = 0; - ret = umsdos_find (demd, info); - if (ret == -ENOENT || ret == 0) { - info->entry.name_len = sprintf (info->entry.name, - "..LINK%ld", info->f_pos); - ret = 0; - } -out: - return ret; -} - - -/* - * Remove an entry from the EMD file. - * Return 0 if OK, a negative error code otherwise. - * - * Complete the information missing in info. - */ - -int umsdos_delentry (struct dentry *parent, struct umsdos_info *info, int isdir) -{ - int ret; - struct dentry *demd = umsdos_get_emd_dentry(parent); - - ret = PTR_ERR(demd); - if (IS_ERR(demd)) - goto out; - ret = umsdos_find (demd, info); - if (ret) - goto out; - if (info->entry.name_len == 0) - goto out; - - if ((isdir != 0) != (S_ISDIR (info->entry.mode) != 0)) { - if (S_ISDIR (info->entry.mode)) { - ret = -EISDIR; - } else { - ret = -ENOTDIR; - } - goto out; - } - ret = umsdos_writeentry (parent, info, 1); - -out: - return ret; -} - - -/* - * Verify that an EMD directory is empty. - * Return: - * 0 if not empty, - * 1 if empty (except for EMD file), - * 2 if empty or no EMD file. - */ - -int umsdos_isempty (struct dentry *dentry) -{ - struct dentry *demd; - int ret = 2; - loff_t pos = 0; - - demd = umsdos_get_emd_dentry(dentry); - if (IS_ERR(demd)) - goto out; - /* If the EMD file does not exist, it is certainly empty. :-) */ - if (!demd->d_inode) - goto out_dput; - - ret = 1; - while (pos < demd->d_inode->i_size) { - struct umsdos_dirent entry; - - if (umsdos_emd_dir_readentry (demd, &pos, &entry) != 0) { - ret = 0; - break; - } - if (entry.name_len != 0) { - ret = 0; - break; - } - } - -out_dput: - dput(demd); -out: - return ret; -} - -/* - * Locate an entry in a EMD directory. - * Return 0 if OK, error code if not, generally -ENOENT. - * - * expect argument: - * 0: anything - * 1: file - * 2: directory - */ - -int umsdos_findentry (struct dentry *parent, struct umsdos_info *info, - int expect) -{ - int ret; - struct dentry *demd = umsdos_get_emd_dentry(parent); - - ret = PTR_ERR(demd); - if (IS_ERR(demd)) - goto out; - ret = umsdos_find (demd, info); - if (ret) - goto out; - - switch (expect) { - case 1: - if (S_ISDIR (info->entry.mode)) - ret = -EISDIR; - break; - case 2: - if (!S_ISDIR (info->entry.mode)) - ret = -ENOTDIR; - } - -out: - Printk (("umsdos_findentry: returning %d\n", ret)); - return ret; -} diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c deleted file mode 100644 index 778feedf4642..000000000000 --- a/fs/umsdos/inode.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - * linux/fs/umsdos/inode.c - * - * Written 1993 by Jacques Gelinas - * Inspired from linux/fs/msdos/... by Werner Almesberger - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct dentry_operations umsdos_dentry_operations; - -struct dentry *saved_root; /* Original root if changed */ -struct inode *pseudo_root; /* Useful to simulate the pseudo DOS */ - /* directory. See UMSDOS_readdir_x() */ - -static struct dentry *check_pseudo_root(struct super_block *); - - -void UMSDOS_put_inode (struct inode *inode) -{ - PRINTK ((KERN_DEBUG - "put inode %p (%lu) pos %lu count=%d\n" - ,inode, inode->i_ino - ,UMSDOS_I(inode)->pos - ,atomic_read(&inode->i_count))); - - if (inode == pseudo_root) { - Printk ((KERN_ERR "Umsdos: debug: releasing pseudo_root - ino=%lu count=%d\n", inode->i_ino, atomic_read(&inode->i_count))); - } - - if (atomic_read(&inode->i_count) == 1) - UMSDOS_I(inode)->i_patched = 0; -} - - -void UMSDOS_put_super (struct super_block *sb) -{ - Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n")); - if (saved_root && pseudo_root && kdev_same(sb->s_dev, ROOT_DEV)) { - shrink_dcache_parent(saved_root); - dput(saved_root); - saved_root = NULL; - pseudo_root = NULL; - } - fat_put_super (sb); -} - - -/* - * Complete the setup of a directory dentry based on its - * EMD/non-EMD status. If it has an EMD, then plug the - * umsdos function table. If not, use the msdos one. - */ -void umsdos_setup_dir(struct dentry *dir) -{ - struct inode *inode = dir->d_inode; - struct umsdos_inode_info *ui = UMSDOS_I(inode); - - if (!S_ISDIR(inode->i_mode)) - printk(KERN_ERR "umsdos_setup_dir: %s/%s not a dir!\n", - dir->d_parent->d_name.name, dir->d_name.name); - - init_waitqueue_head (&ui->dir_info.p); - ui->dir_info.looking = 0; - ui->dir_info.creating = 0; - ui->dir_info.pid = 0; - - inode->i_op = &umsdos_rdir_inode_operations; - inode->i_fop = &umsdos_rdir_operations; - if (umsdos_have_emd(dir)) { -Printk((KERN_DEBUG "umsdos_setup_dir: %s/%s using EMD\n", -dir->d_parent->d_name.name, dir->d_name.name)); - inode->i_op = &umsdos_dir_inode_operations; - inode->i_fop = &umsdos_dir_operations; - } -} - - -/* - * Add some info into an inode so it can find its owner quickly - */ -void umsdos_set_dirinfo_new (struct dentry *dentry, off_t f_pos) -{ - struct inode *inode = dentry->d_inode; - struct dentry *demd; - - UMSDOS_I(inode)->pos = f_pos; - - /* now check the EMD file */ - demd = umsdos_get_emd_dentry(dentry->d_parent); - if (!IS_ERR(demd)) { - dput(demd); - } - return; -} - -static struct inode_operations umsdos_file_inode_operations = { - .truncate = fat_truncate, - .setattr = UMSDOS_notify_change, -}; - -static struct inode_operations umsdos_symlink_inode_operations = { - .readlink = page_readlink, - .follow_link = page_follow_link, - .setattr = UMSDOS_notify_change, -}; - -/* - * Connect the proper tables in the inode and add some info. - */ -/* #Specification: inode / umsdos info - * The first time an inode is seen (inode->i_count == 1), - * the inode number of the EMD file which controls this inode - * is tagged to this inode. It allows operations such as - * notify_change to be handled. - */ -void umsdos_patch_dentry_inode(struct dentry *dentry, off_t f_pos) -{ - struct inode *inode = dentry->d_inode; - -PRINTK (("umsdos_patch_dentry_inode: inode=%lu\n", inode->i_ino)); - - /* - * Classify the inode based on EMD/non-EMD status. - */ -PRINTK (("umsdos_patch_inode: call umsdos_set_dirinfo_new(%p,%lu)\n", -dentry, f_pos)); - umsdos_set_dirinfo_new(dentry, f_pos); - - inode->i_op = &umsdos_file_inode_operations; - if (S_ISREG (inode->i_mode)) { - /* address_space operations already set */ - } else if (S_ISDIR (inode->i_mode)) { - umsdos_setup_dir(dentry); - } else if (S_ISLNK (inode->i_mode)) { - /* address_space operations already set */ - inode->i_op = &umsdos_symlink_inode_operations; - } else - init_special_inode(inode, inode->i_mode, - kdev_t_to_nr(inode->i_rdev)); -} - - -/* - * lock the parent dir before starting ... - * also handles hardlink converting - */ -int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr) -{ - struct inode *dir, *inode; - struct umsdos_info info; - struct dentry *temp, *old_dentry = NULL; - int ret; - - lock_kernel(); - - ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, - &info); - if (ret) - goto out; - ret = umsdos_findentry (dentry->d_parent, &info, 0); - if (ret) { -printk("UMSDOS_notify_change: %s/%s not in EMD, ret=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, ret); - goto out; - } - - if (info.entry.flags & UMSDOS_HLINK) { - /* - * In order to get the correct (real) inode, we just drop - * the original dentry. - */ - d_drop(dentry); -Printk(("UMSDOS_notify_change: hard link %s/%s, fake=%s\n", -dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname)); - - /* Do a real lookup to get the short name dentry */ - temp = umsdos_covered(dentry->d_parent, info.fake.fname, - info.fake.len); - ret = PTR_ERR(temp); - if (IS_ERR(temp)) - goto out; - - /* now resolve the link ... */ - temp = umsdos_solve_hlink(temp); - ret = PTR_ERR(temp); - if (IS_ERR(temp)) - goto out; - old_dentry = dentry; - dentry = temp; /* so umsdos_notify_change_locked will operate on that */ - } - - dir = dentry->d_parent->d_inode; - inode = dentry->d_inode; - - ret = inode_change_ok (inode, attr); - if (ret) - goto out; - - ret = umsdos_notify_change_locked(dentry, attr); - if (ret == 0) - ret = inode_setattr (inode, attr); -out: - if (old_dentry) - dput (dentry); /* if we had to use fake dentry for hardlinks, dput() it now */ - unlock_kernel(); - return ret; -} - - -/* - * Must be called with the parent lock held. - */ -int umsdos_notify_change_locked(struct dentry *dentry, struct iattr *attr) -{ - struct inode *inode = dentry->d_inode; - struct dentry *demd; - struct address_space *mapping; - struct page *page; - int ret = 0; - struct umsdos_dirent *entry; - int offs; - -Printk(("UMSDOS_notify_change: entering for %s/%s (%d)\n", -dentry->d_parent->d_name.name, dentry->d_name.name, UMSDOS_I(inode)->i_patched)); - - if (inode->i_nlink == 0) - goto out; - if (inode->i_ino == UMSDOS_ROOT_INO) - goto out; - - /* get the EMD file dentry */ - demd = umsdos_get_emd_dentry(dentry->d_parent); - ret = PTR_ERR(demd); - if (IS_ERR(demd)) - goto out; - ret = 0; - /* don't do anything if directory is not promoted to umsdos yet */ - if (!demd->d_inode) { - Printk((KERN_DEBUG - "UMSDOS_notify_change: no EMD file %s/%s\n", - demd->d_parent->d_name.name, demd->d_name.name)); - goto out_dput; - } - - /* don't do anything if this is the EMD itself */ - if (inode == demd->d_inode) - goto out_dput; - - /* This inode is not a EMD file nor an inode used internally - * by MSDOS, so we can update its status. - * See emd.c - */ - - /* Read only the start of the entry since we don't touch the name */ - mapping = demd->d_inode->i_mapping; - offs = UMSDOS_I(inode)->pos & ~PAGE_CACHE_MASK; - ret = -ENOMEM; - page=grab_cache_page(mapping,UMSDOS_I(inode)->pos>>PAGE_CACHE_SHIFT); - if (!page) - goto out_dput; - ret=mapping->a_ops->prepare_write(NULL,page,offs,offs+UMSDOS_REC_SIZE); - if (ret) - goto out_unlock; - entry = (struct umsdos_dirent *) (page_address(page) + offs); - if (attr->ia_valid & ATTR_UID) - entry->uid = cpu_to_le16(attr->ia_uid); - if (attr->ia_valid & ATTR_GID) - entry->gid = cpu_to_le16(attr->ia_gid); - if (attr->ia_valid & ATTR_MODE) - entry->mode = cpu_to_le16(attr->ia_mode); - if (attr->ia_valid & ATTR_ATIME) - entry->atime = cpu_to_le32(attr->ia_atime); - if (attr->ia_valid & ATTR_MTIME) - entry->mtime = cpu_to_le32(attr->ia_mtime); - if (attr->ia_valid & ATTR_CTIME) - entry->ctime = cpu_to_le32(attr->ia_ctime); - entry->nlink = cpu_to_le16(inode->i_nlink); - ret=mapping->a_ops->commit_write(NULL,page,offs,offs+UMSDOS_REC_SIZE); - if (ret) - printk(KERN_WARNING - "umsdos_notify_change: %s/%s EMD write error, ret=%d\n", - dentry->d_parent->d_name.name, dentry->d_name.name,ret); - - /* #Specification: notify_change / msdos fs - * notify_change operation are done only on the - * EMD file. The msdos fs is not even called. - */ -out_unlock: - unlock_page(page); - page_cache_release(page); -out_dput: - dput(demd); -out: - return ret; -} - - -/* - * Update the disk with the inode content - */ -int UMSDOS_write_inode (struct inode *inode, int wait) -{ - struct iattr newattrs; - int ret; - - ret = fat_write_inode (inode, wait); - newattrs.ia_mtime = inode->i_mtime; - newattrs.ia_atime = inode->i_atime; - newattrs.ia_ctime = inode->i_ctime; - newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME; - /* - * UMSDOS_notify_change is convenient to call here - * to update the EMD entry associated with this inode. - * But it has the side effect to re"dirt" the inode. - */ -/* - * UMSDOS_notify_change (inode, &newattrs); - - * inode->i_state &= ~I_DIRTY; / * FIXME: this doesn't work. We need to remove ourselves from list on dirty inodes. /mn/ */ - return ret; -} - - -static struct super_operations umsdos_sops = -{ - .write_inode = UMSDOS_write_inode, - .put_inode = UMSDOS_put_inode, - .delete_inode = fat_delete_inode, - .put_super = UMSDOS_put_super, - .statfs = UMSDOS_statfs, - .clear_inode = fat_clear_inode, -}; - -int UMSDOS_statfs(struct super_block *sb,struct statfs *buf) -{ - int ret; - ret = fat_statfs (sb, buf); - if (!ret) - buf->f_namelen = UMSDOS_MAXNAME; - return ret; -} - -/* - * Read the super block of an Extended MS-DOS FS. - */ -struct super_block *UMSDOS_read_super (struct super_block *sb, void *data, - int silent) -{ - struct super_block *res; - struct dentry *new_root; - - /* - * Call msdos-fs to mount the disk. - * Note: this returns res == sb or NULL - */ - MSDOS_SB(sb)->options.isvfat = 0; - res = fat_read_super(sb, data, silent, &umsdos_rdir_inode_operations); - - if (IS_ERR(res)) - return NULL; - if (res == NULL) { - if (!silent) - printk(KERN_INFO "VFS: Can't find a valid " - "UMSDOS filesystem on dev %s.\n", sb->s_id); - return NULL; - } - - printk (KERN_INFO "UMSDOS 0.86k " - "(compatibility level %d.%d, fast msdos)\n", - UMSDOS_VERSION, UMSDOS_RELEASE); - - sb->s_op = &umsdos_sops; - MSDOS_SB(sb)->options.dotsOK = 0; /* disable hidden==dotfile */ - - /* install our dentry operations ... */ - sb->s_root->d_op = &umsdos_dentry_operations; - - umsdos_patch_dentry_inode(sb->s_root, 0); - - /* Check whether to change to the /linux root */ - new_root = check_pseudo_root(sb); - - if (new_root) { - /* sanity check */ - if (new_root->d_op != &umsdos_dentry_operations) - printk("umsdos_read_super: pseudo-root wrong ops!\n"); - - pseudo_root = new_root->d_inode; - saved_root = sb->s_root; - printk(KERN_INFO "UMSDOS: changed to alternate root\n"); - dget (sb->s_root); sb->s_root = dget(new_root); - } - return sb; -} - -/* - * Check for an alternate root if we're the root device. - */ - -extern kdev_t ROOT_DEV; -static struct dentry *check_pseudo_root(struct super_block *sb) -{ - struct dentry *root, *sbin, *init; - - /* - * Check whether we're mounted as the root device. - * must check like this, because we can be used with initrd - */ - - if (!kdev_same(sb->s_dev, ROOT_DEV)) - goto out_noroot; - - /* - * lookup_dentry needs a (so far non-existent) root. - */ - printk(KERN_INFO "check_pseudo_root: mounted as root\n"); - root = lookup_one_len(UMSDOS_PSDROOT_NAME, sb->s_root,UMSDOS_PSDROOT_LEN); - if (IS_ERR(root)) - goto out_noroot; - - if (!root->d_inode || !S_ISDIR(root->d_inode->i_mode)) - goto out_dput; - -printk(KERN_INFO "check_pseudo_root: found %s/%s\n", -root->d_parent->d_name.name, root->d_name.name); - - /* look for /sbin/init */ - sbin = lookup_one_len("sbin", root, 4); - if (IS_ERR(sbin)) - goto out_dput; - if (!sbin->d_inode || !S_ISDIR(sbin->d_inode->i_mode)) - goto out_dput_sbin; - init = lookup_one_len("init", sbin, 4); - if (IS_ERR(init)) - goto out_dput_sbin; - if (!init->d_inode) - goto out_dput_init; - printk(KERN_INFO "check_pseudo_root: found %s/%s, enabling pseudo-root\n", init->d_parent->d_name.name, init->d_name.name); - dput(sbin); - dput(init); - return root; - - /* Alternate root not found ... */ -out_dput_init: - dput(init); -out_dput_sbin: - dput(sbin); -out_dput: - dput(root); -out_noroot: - return NULL; -} - - -static DECLARE_FSTYPE_DEV(umsdos_fs_type, "umsdos", UMSDOS_read_super); - -static int __init init_umsdos_fs (void) -{ - return register_filesystem (&umsdos_fs_type); -} - -static void __exit exit_umsdos_fs (void) -{ - unregister_filesystem (&umsdos_fs_type); -} - -module_init(init_umsdos_fs) -module_exit(exit_umsdos_fs) -MODULE_LICENSE("GPL"); diff --git a/fs/umsdos/ioctl.c b/fs/umsdos/ioctl.c deleted file mode 100644 index fc300030afd1..000000000000 --- a/fs/umsdos/ioctl.c +++ /dev/null @@ -1,446 +0,0 @@ -/* - * linux/fs/umsdos/ioctl.c - * - * Written 1993 by Jacques Gelinas - * - * Extended MS-DOS ioctl directory handling functions - * - * Changes: - * 11/07/2003 Daniele Bellucci - * - audit copy_to_user/put_user in umsdos_ioctl_fill. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -struct UMSDOS_DIR_ONCE { - struct dirent *ent; - int count; -}; - -/* - * Record a single entry the first call. - * Return -EINVAL the next one. - */ -static int umsdos_ioctl_fill ( - void *buf, - const char *name, - int name_len, - loff_t offset, - ino_t ino, - unsigned type) -{ - int ret = -EINVAL; - struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf; - - if (d->count == 0) { - if (copy_to_user (d->ent->d_name, name, name_len) || - put_user ('\0', d->ent->d_name + name_len) || - put_user (name_len, &d->ent->d_reclen) || - put_user (ino, &d->ent->d_ino) || - put_user (offset, &d->ent->d_off)) - return -EFAULT; - d->count = 1; - ret = 0; - } - return ret; -} - - -/* - * Perform special function on a directory - */ -/* #Specification: ioctl / prototypes - * The official prototype for the umsdos ioctl on directory - * is: - * - * int ioctl ( - * int fd, // File handle of the directory - * int cmd, // command - * struct umsdos_ioctl *data) - * - * The struct and the commands are defined in linux/umsdos_fs.h. - * - * umsdos_progs/umsdosio.c provide an interface in C++ to all - * these ioctl. umsdos_progs/udosctl is a small utility showing - * all this. - * - * These ioctl generally allow one to work on the EMD or the - * DOS directory independently. These are essential to implement - * the synchronise. - */ -int UMSDOS_ioctl_dir(struct inode *dir, struct file *filp, unsigned int cmd, - unsigned long data_ptr) -{ - struct dentry *dentry = filp->f_dentry; - struct umsdos_ioctl *idata = (struct umsdos_ioctl *) data_ptr; - int ret; - struct umsdos_ioctl data; - -Printk(("UMSDOS_ioctl_dir: %s/%s, cmd=%d, data=%08lx\n", -dentry->d_parent->d_name.name, dentry->d_name.name, cmd, data_ptr)); - - /* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */ - if (cmd != UMSDOS_GETVERSION - && cmd != UMSDOS_READDIR_DOS - && cmd != UMSDOS_READDIR_EMD - && cmd != UMSDOS_INIT_EMD - && cmd != UMSDOS_CREAT_EMD - && cmd != UMSDOS_RENAME_DOS - && cmd != UMSDOS_UNLINK_EMD - && cmd != UMSDOS_UNLINK_DOS - && cmd != UMSDOS_RMDIR_DOS - && cmd != UMSDOS_STAT_DOS - && cmd != UMSDOS_DOS_SETUP) - return fat_dir_ioctl (dir, filp, cmd, data_ptr); - - /* #Specification: ioctl / access - * Only root (effective id) is allowed to do IOCTL on directory - * in UMSDOS. EPERM is returned for other user. - */ - /* - * Well, not all cases require write access, but it simplifies - * the code, and let's face it, there is only one client (umssync) - * for all this. - */ - ret = verify_area (VERIFY_WRITE, (void *) data_ptr, - sizeof (struct umsdos_ioctl)); - if (ret < 0) - goto out; - - ret = -EPERM; - if (current->euid != 0 && cmd != UMSDOS_GETVERSION) - goto out; - - ret = -EINVAL; - if (cmd == UMSDOS_GETVERSION) { - /* #Specification: ioctl / UMSDOS_GETVERSION - * The field version and release of the structure - * umsdos_ioctl are filled with the version and release - * number of the fs code in the kernel. This will allow - * some form of checking. Users won't be able to run - * incompatible utility such as the synchroniser (umssync). - * umsdos_progs/umsdosio.c enforce this checking. - * - * Return always 0. - */ - put_user (UMSDOS_VERSION, &idata->version); - put_user (UMSDOS_RELEASE, &idata->release); - ret = 0; - goto out; - } - if (cmd == UMSDOS_READDIR_DOS) { - /* #Specification: ioctl / UMSDOS_READDIR_DOS - * One entry is read from the DOS directory at the current - * file position. The entry is put as is in the dos_dirent - * field of struct umsdos_ioctl. - * - * Return > 0 if success. - */ - struct UMSDOS_DIR_ONCE bufk; - - bufk.count = 0; - bufk.ent = &idata->dos_dirent; - - fat_readdir (filp, &bufk, umsdos_ioctl_fill); - - ret = bufk.count == 1 ? 1 : 0; - goto out; - } - if (cmd == UMSDOS_READDIR_EMD) { - /* #Specification: ioctl / UMSDOS_READDIR_EMD - * One entry is read from the EMD at the current - * file position. The entry is put as is in the umsdos_dirent - * field of struct umsdos_ioctl. The corresponding mangled - * DOS entry name is put in the dos_dirent field. - * - * All entries are read including hidden links. Blank - * entries are skipped. - * - * Return > 0 if success. - */ - struct dentry *demd; - loff_t pos = filp->f_pos; - - /* The absence of the EMD is simply seen as an EOF */ - demd = umsdos_get_emd_dentry(dentry); - ret = PTR_ERR(demd); - if (IS_ERR(demd)) - goto out; - ret = 0; - if (!demd->d_inode) - goto read_dput; - - while (pos < demd->d_inode->i_size) { - off_t f_pos = pos; - struct umsdos_dirent entry; - struct umsdos_info info; - - ret = umsdos_emd_dir_readentry (demd, &pos, &entry); - - if (ret == -ENAMETOOLONG) { - printk (KERN_INFO "Fixing EMD entry with invalid size -- zeroing out\n"); - memset (&info, 0, sizeof (info)); - info.f_pos = f_pos; - info.recsize = UMSDOS_REC_SIZE; - ret = umsdos_writeentry (dentry, &info, 1); - continue; - } - - if (ret) - break; - if (entry.name_len <= 0) - continue; - - umsdos_parse (entry.name, entry.name_len, &info); - info.f_pos = f_pos; - umsdos_manglename (&info); - ret = -EFAULT; - if (copy_to_user (&idata->umsdos_dirent, &entry, - sizeof (entry))) - break; - if (copy_to_user (&idata->dos_dirent.d_name, - info.fake.fname, - info.fake.len + 1)) - break; - ret = entry.name_len; - break; - } - /* update the original f_pos */ - filp->f_pos = pos; - read_dput: - d_drop(demd); - dput(demd); - goto out; - } - if (cmd == UMSDOS_INIT_EMD) { - /* #Specification: ioctl / UMSDOS_INIT_EMD - * The UMSDOS_INIT_EMD command makes sure the EMD - * exists for a directory. If it does not, it is - * created. Also, it makes sure the directory function - * table (struct inode_operations) is set to the UMSDOS - * semantic. This mean that umssync may be applied to - * an "opened" msdos directory, and it will change behavior - * on the fly. - * - * Return 0 if success. - */ - - ret = umsdos_make_emd(dentry); -Printk(("UMSDOS_ioctl_dir: INIT_EMD %s/%s, ret=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, ret)); - umsdos_setup_dir (dentry); - goto out; - } - - ret = -EFAULT; - if (copy_from_user (&data, idata, sizeof (data))) - goto out; - - if (cmd == UMSDOS_CREAT_EMD) { - /* #Specification: ioctl / UMSDOS_CREAT_EMD - * The umsdos_dirent field of the struct umsdos_ioctl is used - * as is to create a new entry in the EMD of the directory. - * The DOS directory is not modified. - * No validation is done (yet). - * - * Return 0 if success. - */ - struct umsdos_info info; - - /* This makes sure info.entry and info in general - * is correctly initialised - */ - memcpy (&info.entry, &data.umsdos_dirent, - sizeof (data.umsdos_dirent)); - umsdos_parse (data.umsdos_dirent.name - ,data.umsdos_dirent.name_len, &info); - ret = umsdos_newentry (dentry, &info); - goto out; - } - else if (cmd == UMSDOS_RENAME_DOS) { - struct dentry *old_dentry, *new_dentry; /* FIXME */ - - /* #Specification: ioctl / UMSDOS_RENAME_DOS - * A file or directory is renamed in a DOS directory - * (not moved across directory). The source name - * is in the dos_dirent.name field and the destination - * is in umsdos_dirent.name field. - * - * This ioctl allows umssync to rename a mangled file - * name before syncing it back in the EMD. - */ - old_dentry = umsdos_lookup_dentry (dentry, - data.dos_dirent.d_name, - data.dos_dirent.d_reclen ,1); - ret = PTR_ERR(old_dentry); - if (IS_ERR(old_dentry)) - goto out; - new_dentry = umsdos_lookup_dentry (dentry, - data.umsdos_dirent.name, - data.umsdos_dirent.name_len, 1); - ret = PTR_ERR(new_dentry); - if (!IS_ERR(new_dentry)) { -printk("umsdos_ioctl: renaming %s/%s to %s/%s\n", -old_dentry->d_parent->d_name.name, old_dentry->d_name.name, -new_dentry->d_parent->d_name.name, new_dentry->d_name.name); - ret = msdos_rename (dir, old_dentry, dir, new_dentry); - d_drop(new_dentry); - d_drop(old_dentry); - dput(new_dentry); - } - dput(old_dentry); - goto out; - } - else if (cmd == UMSDOS_UNLINK_EMD) { - /* #Specification: ioctl / UMSDOS_UNLINK_EMD - * The umsdos_dirent field of the struct umsdos_ioctl is used - * as is to remove an entry from the EMD of the directory. - * No validation is done (yet). The mode field is used - * to validate S_ISDIR or S_ISREG. - * - * Return 0 if success. - */ - struct umsdos_info info; - - /* This makes sure info.entry and info in general - * is correctly initialised - */ - memcpy (&info.entry, &data.umsdos_dirent, - sizeof (data.umsdos_dirent)); - umsdos_parse (data.umsdos_dirent.name, - data.umsdos_dirent.name_len, &info); - ret = umsdos_delentry (dentry, &info, - S_ISDIR (data.umsdos_dirent.mode)); - if (ret) { - printk(KERN_WARNING - "umsdos_ioctl: delentry %s/%s failed, ret=%d\n", - dentry->d_name.name, info.entry.name, ret); - } - goto out; - } - else if (cmd == UMSDOS_UNLINK_DOS) { - struct dentry *temp; - - /* #Specification: ioctl / UMSDOS_UNLINK_DOS - * The dos_dirent field of the struct umsdos_ioctl is used to - * execute a msdos_unlink operation. The d_name and d_reclen - * fields are used. - * - * Return 0 if success. - */ - temp = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name, - data.dos_dirent.d_reclen, 1); - ret = PTR_ERR(temp); - if (IS_ERR(temp)) - goto out; - ret = -ENOENT; - if (temp->d_inode) { - ret = -EISDIR; - if (!S_ISDIR(temp->d_inode->i_mode)) - ret = msdos_unlink (dir, temp); - if (!ret) - d_delete(temp); - } - dput (temp); - goto out; - } - else if (cmd == UMSDOS_RMDIR_DOS) { - struct dentry *temp; - - /* #Specification: ioctl / UMSDOS_RMDIR_DOS - * The dos_dirent field of the struct umsdos_ioctl is used to - * execute a msdos_rmdir operation. The d_name and d_reclen - * fields are used. - * - * Return 0 if success. - */ - temp = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name, - data.dos_dirent.d_reclen, 1); - ret = PTR_ERR(temp); - if (IS_ERR(temp)) - goto out; - ret = -ENOENT; - if (temp->d_inode) { - ret = -ENOTDIR; - if (S_ISDIR(temp->d_inode->i_mode)) - ret = msdos_rmdir (dir, temp); - if (!ret) - d_delete(temp); - } - dput (temp); - goto out; - - } else if (cmd == UMSDOS_STAT_DOS) { - /* #Specification: ioctl / UMSDOS_STAT_DOS - * The dos_dirent field of the struct umsdos_ioctl is - * used to execute a stat operation in the DOS directory. - * The d_name and d_reclen fields are used. - * - * The following field of umsdos_ioctl.stat are filled. - * - * st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime, - * Return 0 if success. - */ - struct dentry *dret; - struct inode *inode; - - dret = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name, - data.dos_dirent.d_reclen, 1); - ret = PTR_ERR(dret); - if (IS_ERR(dret)) - goto out; - ret = -ENOENT; - inode = dret->d_inode; - if (inode) { - data.stat.st_ino = inode->i_ino; - data.stat.st_mode = inode->i_mode; - data.stat.st_size = inode->i_size; - data.stat.st_atime = inode->i_atime; - data.stat.st_ctime = inode->i_ctime; - data.stat.st_mtime = inode->i_mtime; - ret = -EFAULT; - if (!copy_to_user (&idata->stat, &data.stat, - sizeof (data.stat))) - ret = 0; - } - dput(dret); - goto out; - } - else if (cmd == UMSDOS_DOS_SETUP) { - /* #Specification: ioctl / UMSDOS_DOS_SETUP - * The UMSDOS_DOS_SETUP ioctl allow changing the - * default permission of the MS-DOS filesystem driver - * on the fly. The MS-DOS driver applies global permissions - * to every file and directory. Normally these permissions - * are controlled by a mount option. This is not - * available for root partition, so a special utility - * (umssetup) is provided to do this, normally in - * /etc/rc.local. - * - * Be aware that this applies ONLY to MS-DOS directories - * (those without EMD --linux-.---). Umsdos directory - * have independent (standard) permission for each - * and every file. - * - * The field umsdos_dirent provide the information needed. - * umsdos_dirent.uid and gid sets the owner and group. - * umsdos_dirent.mode set the permissions flags. - */ - dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid; - dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid; - dir->i_sb->u.msdos_sb.options.fs_fmask = - dir->i_sb->u.msdos_sb.options.fs_dmask = - data.umsdos_dirent.mode; - ret = 0; - } -out: - Printk (("ioctl %d, returning %d\n", cmd, ret)); - return ret; -} diff --git a/fs/umsdos/mangle.c b/fs/umsdos/mangle.c deleted file mode 100644 index 0451123594d9..000000000000 --- a/fs/umsdos/mangle.c +++ /dev/null @@ -1,522 +0,0 @@ -/* - * linux/fs/umsdos/mangle.c - * - * Written 1993 by Jacques Gelinas - * - * Control the mangling of file name to fit msdos name space. - * Many optimisations by GLU == dglaude@is1.vub.ac.be (Glaude David) - */ - -#include -#include -#include -#include - -/* (This file is used outside of the kernel) */ -#ifndef __KERNEL__ -#define KERN_WARNING -#endif - -/* - * Complete the mangling of the MSDOS fake name - * based on the position of the entry in the EMD file. - * - * Simply complete the job of umsdos_parse; fill the extension. - * - * Beware that info->f_pos must be set. - */ -void umsdos_manglename (struct umsdos_info *info) -{ - if (info->msdos_reject) { - /* #Specification: file name / non MSDOS conforming / mangling - * Each non MSDOS conforming file has a special extension - * build from the entry position in the EMD file. - * - * This number is then transform in a base 32 number, where - * each digit is expressed like hexadecimal number, using - * digit and letter, except it uses 22 letters from 'a' to 'v'. - * The number 32 comes from 2**5. It is faster to split a binary - * number using a base which is a power of two. And I was 32 - * when I started this project. Pick your answer :-) . - * - * If the result is '0', it is replace with '_', simply - * to make it odd. - * - * This is true for the first two character of the extension. - * The last one is taken from a list of odd character, which - * are: - * - * { } ( ) ! ` ^ & @ - * - * With this scheme, we can produce 9216 ( 9* 32 * 32) - * different extensions which should not clash with any useful - * extension already popular or meaningful. Since most directory - * have much less than 32 * 32 files in it, the first character - * of the extension of any mangled name will be {. - * - * Here are the reason to do this (this kind of mangling). - * - * -The mangling is deterministic. Just by the extension, we - * are able to locate the entry in the EMD file. - * - * -By keeping to beginning of the file name almost unchanged, - * we are helping the MSDOS user. - * - * -The mangling produces names not too ugly, so an msdos user - * may live with it (remember it, type it, etc...). - * - * -The mangling produces names ugly enough so no one will - * ever think of using such a name in real life. This is not - * fool proof. I don't think there is a total solution to this. - */ - int entry_num; - char *pt = info->fake.fname + info->fake.len; - /* lookup for encoding the last character of the extension - * It contains valid character after the ugly one to make sure - * even if someone overflows the 32 * 32 * 9 limit, it still - * does something - */ -#define SPECIAL_MANGLING '{','}','(',')','!','`','^','&','@' - static char lookup3[] = - { - SPECIAL_MANGLING, - /* This is the start of lookup12 */ - '_', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v' - }; - -#define lookup12 (lookup3+9) - entry_num = info->f_pos / UMSDOS_REC_SIZE; - if (entry_num > (9* 32 * 32)){ - printk (KERN_WARNING "UMSDOS: more than 9216 files in a directory.\n" - "This may break the mangling strategy.\n" - "Not a killer problem. See doc.\n"); - } - *pt++ = '.'; - *pt++ = lookup3 [(entry_num >> 10) & 31]; - *pt++ = lookup12[(entry_num >> 5) & 31]; - *pt++ = lookup12[entry_num & 31]; - *pt = '\0'; /* help doing printk */ - info->fake.len += 4; - info->msdos_reject = 0; /* Avoid mangling twice */ - } -} - -/* - * Evaluate the record size needed to store of name of len character. - * The value returned is a multiple of UMSDOS_REC_SIZE. - */ -int umsdos_evalrecsize (int len) -{ - struct umsdos_dirent dirent; - int nbrec = 1 + ((len - 1 + (dirent.name - (char *) &dirent)) - / UMSDOS_REC_SIZE); - - return nbrec * UMSDOS_REC_SIZE; - /* - * GLU This should be inlined or something to speed it up to the max. - * GLU nbrec is absolutely not needed to return the value. - */ -} -#ifdef TEST -int umsdos_evalrecsize_old (int len) -{ - struct umsdos_dirent dirent; - int size = len + (dirent.name - (char *) &dirent); - int nbrec = size / UMSDOS_REC_SIZE; - int extra = size % UMSDOS_REC_SIZE; - - if (extra > 0) - nbrec++; - return nbrec * UMSDOS_REC_SIZE; -} -#endif - - -/* - * Fill the struct info with the full and msdos name of a file - * Return 0 if all is OK, a negative error code otherwise. - */ -int umsdos_parse ( - const char *fname, - int len, - struct umsdos_info *info) -{ - int ret = -ENAMETOOLONG; - - /* #Specification: file name / too long - * If a file name exceed UMSDOS maxima, the file name is silently - * truncated. This makes it conformant with the other file system - * of Linux (minix and ext2 at least). - */ - if (len > UMSDOS_MAXNAME) - len = UMSDOS_MAXNAME; - { - const char *firstpt = NULL; /* First place we saw a "." in fname */ - - /* #Specification: file name / non MSDOS conforming / base length 0 - * file names beginning with a period '.' are invalid for MS-DOS. - * It needs absolutely a base name. So the file name is mangled - */ - int ivldchar = fname[0] == '.'; /* At least one invalid character */ - int msdos_len = len; - int base_len; - - /* - * cardinal_per_size tells if there exists at least one - * DOS pseudo device on length n. See the test below. - */ - static const char cardinal_per_size[9] = - { - 0, 0, 0, 1, 1, 0, 1, 0, 1 - }; - - /* - * lkp translate all character to acceptable character (for DOS). - * When lkp[n] == n, it means also it is an acceptable one. - * So it serves both as a flag and as a translator. - */ - static char lkp[256]; - static char is_init; - - if (!is_init) { - /* - * Initialisation of the array is easier and less error - * prone like this. - */ - int i; - static const char *spc = "\"*+,/:;<=>?[\\]|~"; - - is_init = 1; - for (i = 0; i <= 32; i++) - lkp[i] = '#'; - for (i = 33; i < 'A'; i++) - lkp[i] = (char) i; - for (i = 'A'; i <= 'Z'; i++) - lkp[i] = (char) (i + ('a' - 'A')); - for (i = 'Z' + 1; i < 127; i++) - lkp[i] = (char) i; - for (i = 128; i < 256; i++) - lkp[i] = '#'; - - lkp['.'] = '_'; - while (*spc != '\0') - lkp[(unsigned char) (*spc++)] = '#'; - } - /* GLU - * File names longer than 8+'.'+3 are invalid for MS-DOS, - * so the file name is to be mangled--no further test is needed. - * This speeds up handling of long names. - * The position of the last point is no more necessary anyway. - */ - if (len <= (8 + 1 + 3)) { - const char *pt = fname; - const char *endpt = fname + len; - - while (pt < endpt) { - if (*pt == '.') { - if (firstpt != NULL) { - /* 2 . in a file name. Reject */ - ivldchar = 1; - break; - } else { - int extlen = (int) (endpt - pt); - - firstpt = pt; - if (firstpt - fname > 8) { - /* base name longer than 8: reject */ - ivldchar = 1; - break; - } else if (extlen > 4) { - /* Extension longer than 4 (including .): reject */ - ivldchar = 1; - break; - } else if (extlen == 1) { - /* #Specification: file name / non MSDOS conforming / last char == . - * If the last character of a file name is - * a period, mangling is applied. MS-DOS does - * not support those file names. - */ - ivldchar = 1; - break; - } else if (extlen == 4) { - /* #Specification: file name / non MSDOS conforming / mangling clash - * To avoid clash with the umsdos mangling, any file - * with a special character as the first character - * of the extension will be mangled. This solves the - * following problem: - * - * # - * touch FILE - * # FILE is invalid for DOS, so mangling is applied - * # file.{_1 is created in the DOS directory - * touch file.{_1 - * # To UMSDOS file point to a single DOS entry. - * # So file.{_1 has to be mangled. - * # - */ - static char special[] = - { - SPECIAL_MANGLING, '\0' - }; - - if (strchr (special, firstpt[1]) != NULL) { - ivldchar = 1; - break; - } - } - } - } else if (lkp[(unsigned char) (*pt)] != *pt) { - ivldchar = 1; - break; - } - pt++; - } - } else { - ivldchar = 1; - } - if (ivldchar - || (firstpt == NULL && len > 8) - || (len == UMSDOS_EMD_NAMELEN - && memcmp (fname, UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN) == 0)) { - /* #Specification: file name / --linux-.--- - * The name of the EMD file --linux-.--- is map to a mangled - * name. So UMSDOS does not restrict its use. - */ - /* #Specification: file name / non MSDOS conforming / mangling - * Non MSDOS conforming file names must use some alias to fit - * in the MSDOS name space. - * - * The strategy is simple. The name is simply truncated to - * 8 char. points are replace with underscore and a - * number is given as an extension. This number correspond - * to the entry number in the EMD file. The EMD file - * only need to carry the real name. - * - * Upper case is also converted to lower case. - * Control character are converted to #. - * Spaces are converted to #. - * The following characters are also converted to #. - * # - * " * + , / : ; < = > ? [ \ ] | ~ - * # - * - * Sometimes the problem is not in MS-DOS itself but in - * command.com. - */ - int i; - char *pt = info->fake.fname; - - base_len = msdos_len = (msdos_len > 8) ? 8 : msdos_len; - /* - * There is no '.' any more so we know for a fact that - * the base length is the length. - */ - memcpy (info->fake.fname, fname, msdos_len); - for (i = 0; i < msdos_len; i++, pt++) - *pt = lkp[(unsigned char) (*pt)]; - *pt = '\0'; /* GLU We force null termination. */ - info->msdos_reject = 1; - /* - * The numeric extension is added only when we know - * the position in the EMD file, in umsdos_newentry(), - * umsdos_delentry(), and umsdos_findentry(). - * See umsdos_manglename(). - */ - } else { - /* Conforming MSDOS file name */ - strncpy (info->fake.fname, fname, len); - info->msdos_reject = 0; - base_len = firstpt != NULL ? (int) (firstpt - fname) : len; - } - if (cardinal_per_size[base_len]) { - /* #Specification: file name / MSDOS devices / mangling - * To avoid unreachable file from MS-DOS, any MS-DOS conforming - * file with a basename equal to one of the MS-DOS pseudo - * devices will be mangled. - * - * If a file such as "prn" was created, it would be unreachable - * under MS-DOS because "prn" is assumed to be the printer, even - * if the file does have an extension. - * - * Since the extension is unimportant to MS-DOS, we must patch - * the basename also. We simply insert a minus '-'. To avoid - * conflict with valid file with a minus in front (such as - * "-prn"), we add an mangled extension like any other - * mangled file name. - * - * Here is the list of DOS pseudo devices: - * - * # - * "prn","con","aux","nul", - * "lpt1","lpt2","lpt3","lpt4", - * "com1","com2","com3","com4", - * "clock$" - * # - * - * and some standard ones for common DOS programs - * - * "emmxxxx0","xmsxxxx0","setverxx" - * - * (Thanks to Chris Hall - * for pointing these out to me). - * - * Is there one missing? - */ - /* This table must be ordered by length */ - static const char *tbdev[] = - { - "prn", "con", "aux", "nul", - "lpt1", "lpt2", "lpt3", "lpt4", - "com1", "com2", "com3", "com4", - "clock$", - "emmxxxx0", "xmsxxxx0", "setverxx" - }; - - /* Tell where to find in tbdev[], the first name of */ - /* a certain length */ - static const char start_ind_dev[9] = - { - 0, 0, 0, 4, 12, 12, 13, 13, 16 - }; - char basen[9]; - int i; - - for (i = start_ind_dev[base_len - 1]; i < start_ind_dev[base_len]; i++) { - if (memcmp (info->fake.fname, tbdev[i], base_len) == 0) { - memcpy (basen, info->fake.fname, base_len); - basen[base_len] = '\0'; /* GLU We force null termination. */ - /* - * GLU We do that only if necessary; we try to do the - * GLU simple thing in the usual circumstance. - */ - info->fake.fname[0] = '-'; - strcpy (info->fake.fname + 1, basen); /* GLU We already guaranteed a null would be at the end. */ - msdos_len = (base_len == 8) ? 8 : base_len + 1; - info->msdos_reject = 1; - break; - } - } - } - info->fake.fname[msdos_len] = '\0'; /* Help doing printk */ - /* GLU This zero should (always?) be there already. */ - info->fake.len = msdos_len; - /* Why not use info->fake.len everywhere? Is it longer? - */ - memcpy (info->entry.name, fname, len); - info->entry.name[len] = '\0'; /* for printk */ - info->entry.name_len = len; - ret = 0; - } - /* - * Evaluate how many records are needed to store this entry. - */ - info->recsize = umsdos_evalrecsize (len); - return ret; -} - -#ifdef TEST - -struct MANG_TEST { - char *fname; /* Name to validate */ - int msdos_reject; /* Expected msdos_reject flag */ - char *msname; /* Expected msdos name */ -}; - -struct MANG_TEST tb[] = -{ - "hello", 0, "hello", - "hello.1", 0, "hello.1", - "hello.1_", 0, "hello.1_", - "prm", 0, "prm", - -#ifdef PROPOSITION - "HELLO", 1, "hello", - "Hello.1", 1, "hello.1", - "Hello.c", 1, "hello.c", -#else -/* - * I find the three examples below very unfortunate. I propose to - * convert them to lower case in a quick preliminary pass, then test - * whether there are other troublesome characters. I have not made - * this change, because it is not easy, but I wanted to mention the - * principle. Obviously something like that would increase the chance - * of collisions, for example between "HELLO" and "Hello", but these - * can be treated elsewhere along with the other collisions. - */ - - "HELLO", 1, "hello", - "Hello.1", 1, "hello_1", - "Hello.c", 1, "hello_c", -#endif - - "hello.{_1", 1, "hello_{_", - "hello\t", 1, "hello#", - "hello.1.1", 1, "hello_1_", - "hel,lo", 1, "hel#lo", - "Salut.Tu.vas.bien?", 1, "salut_tu", - ".profile", 1, "_profile", - ".xv", 1, "_xv", - "toto.", 1, "toto_", - "clock$.x", 1, "-clock$", - "emmxxxx0", 1, "-emmxxxx", - "emmxxxx0.abcd", 1, "-emmxxxx", - "aux", 1, "-aux", - "prn", 1, "-prn", - "prn.abc", 1, "-prn", - "PRN", 1, "-prn", - /* - * GLU WARNING: the results of these are different with my version - * GLU of mangling compared to the original one. - * GLU CAUSE: the manner of calculating the baselen variable. - * GLU For you they are always 3. - * GLU For me they are respectively 7, 8, and 8. - - */ - "PRN.abc", 1, "prn_abc", - "Prn.abcd", 1, "prn_abcd", - "prn.abcd", 1, "prn_abcd", - "Prn.abcdefghij", 1, "prn_abcd" -}; - -int main (int argc, char *argv[]) -{ - int i, rold, rnew; - - printf ("Testing the umsdos_parse.\n"); - for (i = 0; i < sizeof (tb) / sizeof (tb[0]); i++) { - struct MANG_TEST *pttb = tb + i; - struct umsdos_info info; - int ok = umsdos_parse (pttb->fname, strlen (pttb->fname), &info); - - if (strcmp (info.fake.fname, pttb->msname) != 0) { - printf ("**** %s -> ", pttb->fname); - printf ("%s <> %s\n", info.fake.fname, pttb->msname); - } else if (info.msdos_reject != pttb->msdos_reject) { - printf ("**** %s -> %s ", pttb->fname, pttb->msname); - printf ("%d <> %d\n", info.msdos_reject, pttb->msdos_reject); - } else { - printf (" %s -> %s %d\n", pttb->fname, pttb->msname - ,pttb->msdos_reject); - } - } - printf ("Testing the new umsdos_evalrecsize."); - for (i = 0; i < UMSDOS_MAXNAME; i++) { - rnew = umsdos_evalrecsize (i); - rold = umsdos_evalrecsize_old (i); - if (!(i % UMSDOS_REC_SIZE)) { - printf ("\n%d:\t", i); - } - if (rnew != rold) { - printf ("**** %d newres: %d != %d \n", i, rnew, rold); - } else { - printf ("."); - } - } - printf ("\nEnd of Testing.\n"); - - return 0; -} - -#endif diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c deleted file mode 100644 index 2d8a64af1aed..000000000000 --- a/fs/umsdos/namei.c +++ /dev/null @@ -1,1124 +0,0 @@ -/* - * linux/fs/umsdos/namei.c - * - * Written 1993 by Jacques Gelinas - * Inspired from linux/fs/msdos/... by Werner Almesberger - * - * Maintain and access the --linux alternate directory file. - */ - /* - * You are in the maze of twisted functions - half of them shouldn't - * be here... - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define UMSDOS_DIR_LOCK - -#ifdef UMSDOS_DIR_LOCK - -static inline void u_sleep_on (struct inode *dir) -{ - sleep_on (&UMSDOS_I(dir)->dir_info.p); -} - -static inline void u_wake_up (struct inode *dir) -{ - wake_up (&UMSDOS_I(dir)->dir_info.p); -} - -/* - * Wait for creation exclusivity. - * Return 0 if the dir was already available. - * Return 1 if a wait was necessary. - * When 1 is return, it means a wait was done. It does not - * mean the directory is available. - */ -static int umsdos_waitcreate (struct inode *dir) -{ - int ret = 0; - - if (UMSDOS_I(dir)->dir_info.creating - && UMSDOS_I(dir)->dir_info.pid != current->pid) { - PRINTK (("creating && dir_info.pid=%lu, current->pid=%u\n", UMSDOS_I(dir)->dir_info.pid, current->pid)); - u_sleep_on (dir); - ret = 1; - } - return ret; -} - -/* - * Wait for any lookup process to finish - */ -static void umsdos_waitlookup (struct inode *dir) -{ - while (UMSDOS_I(dir)->dir_info.looking) { - u_sleep_on (dir); - } -} - -/* - * Lock all other process out of this directory. - */ -/* #Specification: file creation / not atomic - * File creation is a two step process. First we create (allocate) - * an entry in the EMD file and then (using the entry offset) we - * build a unique name for MSDOS. We create this name in the msdos - * space. - * - * We have to use semaphore (sleep_on/wake_up) to prevent lookup - * into a directory when we create a file or directory and to - * prevent creation while a lookup is going on. Since many lookup - * may happen at the same time, the semaphore is a counter. - * - * Only one creation is allowed at the same time. This protection - * may not be necessary. The problem arise mainly when a lookup - * or a readdir is done while a file is partially created. The - * lookup process see that as a "normal" problem and silently - * erase the file from the EMD file. Normal because a file - * may be erased during a MSDOS session, but not removed from - * the EMD file. - * - * The locking is done on a directory per directory basis. Each - * directory inode has its wait_queue. - * - * For some operation like hard link, things even get worse. Many - * creation must occur at once (atomic). To simplify the design - * a process is allowed to recursively lock the directory for - * creation. The pid of the locking process is kept along with - * a counter so a second level of locking is granted or not. - */ -void umsdos_lockcreate (struct inode *dir) -{ - /* - * Wait for any creation process to finish except - * if we (the process) own the lock - */ - while (umsdos_waitcreate (dir) != 0); - UMSDOS_I(dir)->dir_info.creating++; - UMSDOS_I(dir)->dir_info.pid = current->pid; - umsdos_waitlookup (dir); -} - -/* - * Lock all other process out of those two directories. - */ -static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2) -{ - /* - * We must check that both directory are available before - * locking anyone of them. This is to avoid some deadlock. - * Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing - * this to me. - */ - while (1) { - if (umsdos_waitcreate (dir1) == 0 - && umsdos_waitcreate (dir2) == 0) { - /* We own both now */ - UMSDOS_I(dir1)->dir_info.creating++; - UMSDOS_I(dir1)->dir_info.pid = current->pid; - UMSDOS_I(dir2)->dir_info.creating++; - UMSDOS_I(dir2)->dir_info.pid = current->pid; - break; - } - } - umsdos_waitlookup (dir1); - umsdos_waitlookup (dir2); -} - -/* - * Wait until creation is finish in this directory. - */ -void umsdos_startlookup (struct inode *dir) -{ - while (umsdos_waitcreate (dir) != 0); - UMSDOS_I(dir)->dir_info.looking++; -} - -/* - * Unlock the directory. - */ -void umsdos_unlockcreate (struct inode *dir) -{ - UMSDOS_I(dir)->dir_info.creating--; - if (UMSDOS_I(dir)->dir_info.creating < 0) { - printk ("UMSDOS: UMSDOS_I(dir)->dir_info.creating < 0: %d" - ,UMSDOS_I(dir)->dir_info.creating); - } - u_wake_up (dir); -} - -/* - * Tell directory lookup is over. - */ -void umsdos_endlookup (struct inode *dir) -{ - UMSDOS_I(dir)->dir_info.looking--; - if (UMSDOS_I(dir)->dir_info.looking < 0) { - printk ("UMSDOS: UMSDOS_I(dir)->dir_info.looking < 0: %d" - ,UMSDOS_I(dir)->dir_info.looking); - } - u_wake_up (dir); -} - -#else -static void umsdos_lockcreate (struct inode *dir) -{ -} -static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2) -{ -} -void umsdos_startlookup (struct inode *dir) -{ -} -static void umsdos_unlockcreate (struct inode *dir) -{ -} -void umsdos_endlookup (struct inode *dir) -{ -} - -#endif - -static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry, - int errcod) -{ - int ret = 0; - - if (umsdos_is_pseudodos (dir, dentry)) { - /* #Specification: pseudo root / any file creation /DOS - * The pseudo sub-directory /DOS can't be created! - * EEXIST is returned. - * - * The pseudo sub-directory /DOS can't be removed! - * EPERM is returned. - */ - ret = errcod; - } - return ret; -} - -/* - * Add a new file (ordinary or special) into the alternate directory. - * The file is added to the real MSDOS directory. If successful, it - * is then added to the EMD file. - * - * Return the status of the operation. 0 mean success. - * - * #Specification: create / file exists in DOS - * Here is a situation: we are trying to create a file with - * UMSDOS. The file is unknown to UMSDOS but already - * exists in the DOS directory. - * - * Here is what we are NOT doing: - * - * We could silently assume that everything is fine - * and allows the creation to succeed. - * - * It is possible not all files in the partition - * are meant to be visible from linux. By trying to create - * those file in some directory, one user may get access - * to those file without proper permissions. Looks like - * a security hole to me. Off course sharing a file system - * with DOS is some kind of security hole :-) - * - * So ? - * - * We return EEXIST in this case. - * The same is true for directory creation. - */ -static int umsdos_create_any (struct inode *dir, struct dentry *dentry, - int mode, dev_t rdev, char flags) -{ - struct dentry *fake; - struct inode *inode; - int ret; - struct umsdos_info info; - - ret = umsdos_nevercreat (dir, dentry, -EEXIST); - if (ret) - goto out; - - ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); - if (ret) - goto out; - - info.entry.mode = mode; - info.entry.rdev = rdev; - info.entry.flags = flags; - info.entry.uid = current->fsuid; - info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; - info.entry.ctime = info.entry.atime = info.entry.mtime = get_seconds(); - info.entry.nlink = 1; - ret = umsdos_newentry (dentry->d_parent, &info); - if (ret) - goto out; - - /* do a real lookup to get the short name dentry */ - fake = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len); - ret = PTR_ERR(fake); - if (IS_ERR(fake)) - goto out_remove; - - /* should not exist yet ... */ - ret = -EEXIST; - if (fake->d_inode) - goto out_remove_dput; - - ret = msdos_create (dir, fake, S_IFREG | 0777, NULL); - if (ret) - goto out_remove_dput; - - inode = fake->d_inode; - atomic_inc(&inode->i_count); - d_instantiate (dentry, inode); - dput(fake); - if (atomic_read(&inode->i_count) > 1) { - printk(KERN_WARNING - "umsdos_create_any: %s/%s, ino=%ld, icount=%d??\n", - dentry->d_parent->d_name.name, dentry->d_name.name, - inode->i_ino, atomic_read(&inode->i_count)); - } - umsdos_lookup_patch_new(dentry, &info); - -out: - return ret; - - /* Creation failed ... remove the EMD entry */ -out_remove_dput: - dput(fake); -out_remove: - if (ret == -EEXIST) - printk(KERN_WARNING "UMSDOS: out of sync, deleting %s/%s\n", - dentry->d_parent->d_name.name, info.fake.fname); - umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode)); - goto out; -} - -/* - * Add a new file into the alternate directory. - * The file is added to the real MSDOS directory. If successful, it - * is then added to the EMD file. - * - * Return the status of the operation. 0 mean success. - */ -int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) -{ - return umsdos_create_any (dir, dentry, mode, 0, 0); -} - - -/* - * Initialise the new_entry from the old for a rename operation. - * (Only useful for umsdos_rename_f() below). - */ -static void umsdos_ren_init (struct umsdos_info *new_info, - struct umsdos_info *old_info) -{ - new_info->entry.mode = old_info->entry.mode; - new_info->entry.rdev = old_info->entry.rdev; - new_info->entry.uid = old_info->entry.uid; - new_info->entry.gid = old_info->entry.gid; - new_info->entry.ctime = old_info->entry.ctime; - new_info->entry.atime = old_info->entry.atime; - new_info->entry.mtime = old_info->entry.mtime; - new_info->entry.flags = old_info->entry.flags; - new_info->entry.nlink = old_info->entry.nlink; -} - -/* - * Rename a file (move) in the file system. - */ - -static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry, - int flags) -{ - struct inode *old_inode = old_dentry->d_inode; - struct dentry *old, *new, *old_emd; - int err, ret; - struct umsdos_info old_info; - struct umsdos_info new_info; - - ret = -EPERM; - err = umsdos_parse (old_dentry->d_name.name, - old_dentry->d_name.len, &old_info); - if (err) - goto out; - err = umsdos_parse (new_dentry->d_name.name, - new_dentry->d_name.len, &new_info); - if (err) - goto out; - - /* Get the EMD dentry for the old parent */ - old_emd = umsdos_get_emd_dentry(old_dentry->d_parent); - ret = PTR_ERR(old_emd); - if (IS_ERR(old_emd)) - goto out; - - umsdos_lockcreate2 (old_dir, new_dir); - - ret = umsdos_findentry(old_emd->d_parent, &old_info, 0); - if (ret) - goto out_unlock; - - err = umsdos_findentry(new_dentry->d_parent, &new_info, 0); - if (err == 0) { - /* check whether it _really_ exists ... */ - ret = -EEXIST; - if (new_dentry->d_inode) - goto out_unlock; - - /* bogus lookup? complain and fix up the EMD ... */ - printk(KERN_WARNING - "umsdos_rename_f: entry %s/%s exists, inode NULL??\n", - new_dentry->d_parent->d_name.name, new_info.entry.name); - err = umsdos_delentry(new_dentry->d_parent, &new_info, - S_ISDIR(new_info.entry.mode)); - } - - umsdos_ren_init (&new_info, &old_info); - if (flags) - new_info.entry.flags = flags; - ret = umsdos_newentry (new_dentry->d_parent, &new_info); - if (ret) - goto out_unlock; - - /* If we're moving a hardlink, drop it first */ - if (old_info.entry.flags & UMSDOS_HLINK) { - d_drop(old_dentry); - } - - old = umsdos_covered(old_dentry->d_parent, old_info.fake.fname, - old_info.fake.len); - ret = PTR_ERR(old); - if (IS_ERR(old)) - goto out_unlock; - /* make sure it's the same inode! */ - ret = -ENOENT; - /* - * note: for hardlinks they will be different! - * old_inode will contain inode of .LINKxxx file containing data, and - * old->d_inode will contain inode of file containing path to .LINKxxx file - */ - if (!(old_info.entry.flags & UMSDOS_HLINK)) { - if (old->d_inode != old_inode) - goto out_dput; - } - - new = umsdos_covered(new_dentry->d_parent, new_info.fake.fname, - new_info.fake.len); - ret = PTR_ERR(new); - if (IS_ERR(new)) - goto out_dput; - - /* Do the msdos-level rename */ - ret = msdos_rename (old_dir, old, new_dir, new); - - dput(new); - - /* If the rename failed, remove the new EMD entry */ - if (ret != 0) { - umsdos_delentry (new_dentry->d_parent, &new_info, - S_ISDIR (new_info.entry.mode)); - goto out_dput; - } - - /* - * Rename successful ... remove the old name from the EMD. - * Note that we use the EMD parent here, as the old dentry - * may have moved to a new parent ... - */ - err = umsdos_delentry (old_emd->d_parent, &old_info, - S_ISDIR (old_info.entry.mode)); - if (err) { - /* Failed? Complain a bit, but don't fail the operation */ - printk(KERN_WARNING - "umsdos_rename_f: delentry %s/%s failed, error=%d\n", - old_emd->d_parent->d_name.name, old_info.entry.name, - err); - } - - /* - * Update f_pos so notify_change will succeed - * if the file was already in use. - */ - umsdos_set_dirinfo_new(old_dentry, new_info.f_pos); - - /* dput() the dentry if we haven't already */ -out_dput: - dput(old); - -out_unlock: - dput(old_emd); - umsdos_unlockcreate (old_dir); - umsdos_unlockcreate (new_dir); - -out: - Printk ((" _ret=%d\n", ret)); - return ret; -} - -/* - * Setup a Symbolic link or a (pseudo) hard link - * Return a negative error code or 0 if OK. - */ -/* #Specification: symbolic links / strategy - * A symbolic link is simply a file which holds a path. It is - * implemented as a normal MSDOS file (not very space efficient :-() - * - * I see two different ways to do this: One is to place the link data - * in unused entries of the EMD file; the other is to have a separate - * file dedicated to hold all symbolic links data. - * - * Let's go for simplicity... - */ - -/* - * AV. Should be called with dir->i_sem down. - */ -static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry, - const char *symname, int mode, char flags) -{ - int ret, len; - - ret = umsdos_create_any (dir, dentry, mode, 0, flags); - if (ret) { - printk(KERN_WARNING - "umsdos_symlink: create failed, ret=%d\n", ret); - goto out; - } - - len = strlen (symname) + 1; - ret = page_symlink(dentry->d_inode, symname, len); - if (ret < 0) - goto out_unlink; -out: - return ret; - -out_unlink: - printk(KERN_WARNING "umsdos_symlink: write failed, unlinking\n"); - UMSDOS_unlink (dir, dentry); - d_drop(dentry); - goto out; -} - -/* - * Setup a Symbolic link. - * Return a negative error code or 0 if OK. - */ -int UMSDOS_symlink ( struct inode *dir, struct dentry *dentry, - const char *symname) -{ - return umsdos_symlink_x (dir, dentry, symname, S_IFLNK | 0777, 0); -} - -/* - * Add a link to an inode in a directory - */ -int UMSDOS_link (struct dentry *olddentry, struct inode *dir, - struct dentry *dentry) -{ - struct inode *oldinode = olddentry->d_inode; - struct inode *olddir = olddentry->d_parent->d_inode; - struct dentry *temp; - char *path; - unsigned long buffer; - int ret; - struct umsdos_info old_info; - struct umsdos_info hid_info; - -#ifdef UMSDOS_DEBUG_VERBOSE -printk("umsdos_link: new %s/%s -> %s/%s\n", -dentry->d_parent->d_name.name, dentry->d_name.name, -olddentry->d_parent->d_name.name, olddentry->d_name.name); -#endif - - ret = -EPERM; - if (S_ISDIR (oldinode->i_mode)) - goto out; - - ret = umsdos_nevercreat (dir, dentry, -EPERM); - if (ret) - goto out; - - ret = -ENOMEM; - buffer = get_zeroed_page(GFP_KERNEL); - if (!buffer) - goto out; - - /* - * Lock the link parent if it's not the same directory. - */ - ret = -EDEADLOCK; - if (olddir != dir) { - if (atomic_read(&olddir->i_sem.count) < 1) - goto out_free; - down(&olddir->i_sem); - } - - /* - * Parse the name and get the visible directory entry. - */ - ret = umsdos_parse (olddentry->d_name.name, olddentry->d_name.len, - &old_info); - if (ret) - goto out_unlock; - ret = umsdos_findentry (olddentry->d_parent, &old_info, 1); - if (ret) { -printk("UMSDOS_link: %s/%s not in EMD, ret=%d\n", -olddentry->d_parent->d_name.name, olddentry->d_name.name, ret); - goto out_unlock; - } - - /* - * If the visible dentry is a pseudo-hardlink, the original - * file must be already hidden. - */ - if (!(old_info.entry.flags & UMSDOS_HLINK)) { - int err; - - /* create a hidden link name */ - ret = umsdos_newhidden (olddentry->d_parent, &hid_info); - if (ret) { -printk("umsdos_link: can't make hidden %s/%s, ret=%d\n", -olddentry->d_parent->d_name.name, hid_info.entry.name, ret); - goto out_unlock; - } - - /* - * Make a dentry and rename the original file ... - */ - temp = umsdos_lookup_dentry(olddentry->d_parent, - hid_info.entry.name, - hid_info.entry.name_len, 0); - ret = PTR_ERR(temp); - if (IS_ERR(temp)) { -printk("umsdos_link: lookup %s/%s failed, ret=%d\n", -dentry->d_parent->d_name.name, hid_info.entry.name, ret); - goto cleanup; - } - /* rename the link to the hidden location ... */ - ret = umsdos_rename_f(olddir, olddentry, olddir, temp, - UMSDOS_HIDDEN); - d_move(olddentry, temp); - dput(temp); - if (ret) { -printk("umsdos_link: rename to %s/%s failed, ret=%d\n", -temp->d_parent->d_name.name, temp->d_name.name, ret); - goto cleanup; - } - /* mark the inode as a hardlink */ - UMSDOS_I(oldinode)->i_is_hlink = 1; - - /* - * Capture the path to the hidden link. - */ - path = umsdos_d_path(olddentry, (char *) buffer, PAGE_SIZE); -Printk(("umsdos_link: hidden link path=%s\n", path)); - - /* - * Recreate a dentry for the original name and symlink it, - * then symlink the new dentry. Don't give up if one fails, - * or we'll lose the file completely! - * - * Note: this counts as the "original" reference, so we - * don't increment i_nlink for this one. - */ - temp = umsdos_lookup_dentry(olddentry->d_parent, - old_info.entry.name, - old_info.entry.name_len, 0); - ret = PTR_ERR(temp); - if (!IS_ERR(temp)) { - ret = umsdos_symlink_x (olddir, temp, path, - S_IFREG | 0777, UMSDOS_HLINK); - dput(temp); - } - - /* This symlink increments i_nlink (see below.) */ - err = umsdos_symlink_x (dir, dentry, path, - S_IFREG | 0777, UMSDOS_HLINK); - /* fold the two errors */ - if (!ret) - ret = err; - goto out_unlock; - - /* creation failed ... remove the link entry */ - cleanup: -printk("umsdos_link: link failed, ret=%d, removing %s/%s\n", -ret, olddentry->d_parent->d_name.name, hid_info.entry.name); - err = umsdos_delentry(olddentry->d_parent, &hid_info, 0); - goto out_unlock; - } - -Printk(("UMSDOS_link: %s/%s already hidden\n", -olddentry->d_parent->d_name.name, olddentry->d_name.name)); - /* - * The original file is already hidden, and we need to get - * the dentry for its real name, not the visible name. - * N.B. make sure it's the hidden inode ... - */ - if (!UMSDOS_I(oldinode)->i_is_hlink) - printk("UMSDOS_link: %s/%s hidden, ino=%ld not hlink??\n", - olddentry->d_parent->d_name.name, - olddentry->d_name.name, oldinode->i_ino); - - /* - * In order to get the correct (real) inode, we just drop - * the original dentry. - */ - d_drop(olddentry); -Printk(("UMSDOS_link: hard link %s/%s, fake=%s\n", -olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.fake.fname)); - - /* Do a real lookup to get the short name dentry */ - temp = umsdos_covered(olddentry->d_parent, old_info.fake.fname, - old_info.fake.len); - ret = PTR_ERR(temp); - if (IS_ERR(temp)) - goto out_unlock; - - /* now resolve the link ... */ - temp = umsdos_solve_hlink(temp); - ret = PTR_ERR(temp); - if (IS_ERR(temp)) - goto out_unlock; - path = umsdos_d_path(temp, (char *) buffer, PAGE_SIZE); - dput(temp); -Printk(("umsdos_link: %s/%s already hidden, path=%s\n", -olddentry->d_parent->d_name.name, olddentry->d_name.name, path)); - - /* finally we can symlink it ... */ - ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777,UMSDOS_HLINK); - -out_unlock: - /* remain locked for the call to notify_change ... */ - if (ret == 0) { - struct iattr newattrs; - - /* Do a real lookup to get the short name dentry */ - temp = umsdos_covered(olddentry->d_parent, - old_info.fake.fname, - old_info.fake.len); - ret = PTR_ERR(temp); - if (IS_ERR(temp)) - goto out_unlock2; - - /* now resolve the link ... */ - temp = umsdos_solve_hlink(temp); - ret = PTR_ERR(temp); - if (IS_ERR(temp)) - goto out_unlock2; - - -#ifdef UMSDOS_PARANOIA -if (!UMSDOS_I(oldinode)->i_is_hlink) -printk("UMSDOS_link: %s/%s, ino=%ld, not marked as hlink!\n", -olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino); -#endif - temp->d_inode->i_nlink++; -Printk(("UMSDOS_link: linked %s/%s, ino=%ld, nlink=%d\n", -olddentry->d_parent->d_name.name, olddentry->d_name.name, -oldinode->i_ino, oldinode->i_nlink)); - newattrs.ia_valid = 0; - ret = umsdos_notify_change_locked(temp, &newattrs); - if (ret == 0) - mark_inode_dirty(temp->d_inode); - dput(temp); -out_unlock2: - if (ret == 0) - mark_inode_dirty(olddentry->d_inode); - } - if (olddir != dir) - up(&olddir->i_sem); - -out_free: - free_page(buffer); -out: - Printk (("umsdos_link %d\n", ret)); - return ret; -} - - -/* - * Add a sub-directory in a directory - */ -/* #Specification: mkdir / Directory already exist in DOS - * We do the same thing as for file creation. - * For all user it is an error. - */ -/* #Specification: mkdir / umsdos directory / create EMD - * When we created a new sub-directory in a UMSDOS - * directory (one with full UMSDOS semantics), we - * create immediately an EMD file in the new - * sub-directory so it inherits UMSDOS semantics. - */ -int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode) -{ - struct dentry *temp; - struct inode *inode; - int ret, err; - struct umsdos_info info; - - ret = umsdos_nevercreat (dir, dentry, -EEXIST); - if (ret) - goto out; - - ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); - if (ret) - goto out; - - info.entry.mode = mode | S_IFDIR; - info.entry.rdev = 0; - info.entry.uid = current->fsuid; - info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; - info.entry.ctime = info.entry.atime = info.entry.mtime = get_seconds(); - info.entry.flags = 0; - info.entry.nlink = 1; - ret = umsdos_newentry (dentry->d_parent, &info); - if (ret) - goto out; - - /* lookup the short name dentry */ - temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len); - ret = PTR_ERR(temp); - if (IS_ERR(temp)) - goto out_remove; - - /* Make sure the short name doesn't exist */ - ret = -EEXIST; - if (temp->d_inode) { -printk("umsdos_mkdir: short name %s/%s exists\n", -dentry->d_parent->d_name.name, info.fake.fname); - goto out_remove_dput; - } - - ret = msdos_mkdir (dir, temp, mode); - if (ret) - goto out_remove_dput; - - /* - * Lock the inode to protect the EMD creation ... - */ - inode = temp->d_inode; - down(&inode->i_sem); - - atomic_inc(&inode->i_count); - d_instantiate(dentry, inode); - - /* N.B. this should have an option to create the EMD ... */ - umsdos_lookup_patch_new(dentry, &info); - - /* - * Create the EMD file, and set up the dir so it is - * promoted to EMD with the EMD file invisible. - * - * N.B. error return if EMD fails? - */ - err = umsdos_make_emd(dentry); - umsdos_setup_dir(dentry); - - up(&inode->i_sem); - dput(temp); - -out: - Printk(("umsdos_mkdir: %s/%s, ret=%d\n", - dentry->d_parent->d_name.name, dentry->d_name.name, ret)); - return ret; - - /* an error occurred ... remove EMD entry. */ -out_remove_dput: - dput(temp); -out_remove: - umsdos_delentry (dentry->d_parent, &info, 1); - goto out; -} - -/* - * Add a new device special file into a directory. - * - * #Specification: Special files / strategy - * Device special file, pipes, etc ... are created like normal - * file in the msdos file system. Of course they remain empty. - * - * One strategy was to create those files only in the EMD file - * since they were not important for MSDOS. The problem with - * that, is that there were not getting inode number allocated. - * The MSDOS filesystems is playing a nice game to fake inode - * number, so why not use it. - * - * The absence of inode number compatible with those allocated - * for ordinary files was causing major trouble with hard link - * in particular and other parts of the kernel I guess. - */ -int UMSDOS_mknod (struct inode *dir, struct dentry *dentry, - int mode, dev_t rdev) -{ - return umsdos_create_any (dir, dentry, mode, rdev, 0); -} - -/* - * Remove a sub-directory. - */ -int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry) -{ - struct dentry *temp; - int ret, err, empty; - struct umsdos_info info; - - ret = umsdos_nevercreat (dir, dentry, -EPERM); - if (ret) - goto out; - - ret = -EBUSY; - if (!d_unhashed(dentry)) - goto out; - - /* check whether the EMD is empty */ - ret = -ENOTEMPTY; - empty = umsdos_isempty (dentry); - - /* Have to remove the EMD file? */ - if (empty == 1) { - struct dentry *demd; - - demd = umsdos_get_emd_dentry(dentry); - if (!IS_ERR(demd)) { - err = -ENOENT; - if (demd->d_inode) - err = msdos_unlink (dentry->d_inode, demd); -Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err)); -#ifdef UMSDOS_PARANOIA -if (err) -printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n", -demd->d_parent->d_name.name, demd->d_name.name, err); -#endif - if (!err) { - d_delete(demd); - ret = 0; - } - dput(demd); - } - } else if (empty == 2) - ret = 0; - if (ret) - goto out; - - umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); - /* Call findentry to complete the mangling */ - umsdos_findentry (dentry->d_parent, &info, 2); - temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len); - ret = PTR_ERR(temp); - if (IS_ERR(temp)) - goto out; - /* - * Attempt to remove the msdos name. - */ - ret = msdos_rmdir (dir, temp); - if (ret && ret != -ENOENT) - goto out_dput; - - d_delete(temp); - /* OK so far ... remove the name from the EMD */ - ret = umsdos_delentry (dentry->d_parent, &info, 1); -#ifdef UMSDOS_PARANOIA -if (ret) -printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret); -#endif - - /* dput() temp if we didn't do it above */ -out_dput: - dput(temp); - -out: - Printk (("umsdos_rmdir %d\n", ret)); - return ret; -} - - -/* - * Remove a file from the directory. - * - * #Specification: hard link / deleting a link - * When we delete a file and this file is a link, - * we must subtract 1 from the nlink field of the - * hidden link. - * - * If the count goes to 0, we delete this hidden - * link too. - */ -int UMSDOS_unlink (struct inode *dir, struct dentry *dentry) -{ - struct dentry *temp, *link = NULL; - struct inode *inode; - int ret; - struct umsdos_info info; - -Printk(("UMSDOS_unlink: entering %s/%s\n", -dentry->d_parent->d_name.name, dentry->d_name.name)); - - ret = umsdos_nevercreat (dir, dentry, -EPERM); - if (ret) - goto out; - - ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); - if (ret) - goto out; - - umsdos_lockcreate (dir); - ret = umsdos_findentry (dentry->d_parent, &info, 1); - if (ret) { -printk("UMSDOS_unlink: %s/%s not in EMD, ret=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, ret); - goto out_unlock; - } - -Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname)); - - /* - * Note! If this is a hardlink and the names are aliased, - * the short-name lookup will return the hardlink dentry. - * In order to get the correct (real) inode, we just drop - * the original dentry. - */ - if (info.entry.flags & UMSDOS_HLINK) { - d_drop(dentry); - } - - /* Do a real lookup to get the short name dentry */ - temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len); - ret = PTR_ERR(temp); - if (IS_ERR(temp)) - goto out_unlock; - - /* - * Resolve hardlinks now, but defer processing until later. - */ - if (info.entry.flags & UMSDOS_HLINK) { - link = umsdos_solve_hlink(dget(temp)); - } - - /* Delete the EMD entry */ - ret = umsdos_delentry (dentry->d_parent, &info, 0); - if (ret && ret != -ENOENT) { - printk(KERN_WARNING "UMSDOS_unlink: delentry %s, error=%d\n", - info.entry.name, ret); - goto out_dput; - } - - ret = msdos_unlink(dir, temp); - if (!ret) - d_delete(temp); -#ifdef UMSDOS_PARANOIA -if (ret) -printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n", -temp->d_parent->d_name.name, temp->d_name.name, ret); -#endif - - /* dput() temp if we didn't do it above */ -out_dput: - dput(temp); - -out_unlock: - umsdos_unlockcreate (dir); - - /* - * Now check for deferred handling of a hardlink. - */ - if (!link) - goto out; - - if (IS_ERR(link)) { -printk("umsdos_unlink: failed to resolve %s/%s\n", -dentry->d_parent->d_name.name, dentry->d_name.name); - if (!ret) - ret = PTR_ERR(link); - goto out; - } - -Printk(("umsdos_unlink: link %s/%s deferred, pending ret=%d\n", -link->d_parent->d_name.name, link->d_name.name, ret)); - - /* already have an error? */ - if (ret) - goto out_cleanup; - - /* make sure the link exists ... */ - inode = link->d_inode; - if (!inode) { - printk(KERN_WARNING "umsdos_unlink: hard link not found\n"); - goto out_cleanup; - } - - /* - * If this was the last linked reference, delete it now. - * - * N.B. Deadlock problem? We should be holding the lock - * for the hardlink's parent, but another process might - * be holding that lock waiting for us to finish ... - */ - if (inode->i_nlink <= 1) { - ret = UMSDOS_unlink (link->d_parent->d_inode, link); - if (ret) { - printk(KERN_WARNING - "umsdos_unlink: link removal failed, ret=%d\n", - ret); - } else - d_delete(link); - } else { - struct iattr newattrs; - inode->i_nlink--; - newattrs.ia_valid = 0; - ret = umsdos_notify_change_locked(link, &newattrs); - if (!ret) - mark_inode_dirty(link->d_inode); - } - -out_cleanup: - d_drop(link); - dput(link); - -out: - Printk (("umsdos_unlink %d\n", ret)); - return ret; -} - -/* - * Rename (move) a file. - */ -int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) -{ - int ret; - - ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST); - if (ret) - return ret; - - /* - * If the target already exists, delete it first. - */ - if (new_dentry->d_inode) { - dget(new_dentry); - if (S_ISDIR(old_dentry->d_inode->i_mode)) - ret = UMSDOS_rmdir (new_dir, new_dentry); - else - ret = UMSDOS_unlink (new_dir, new_dentry); - if (!ret) - d_drop(new_dentry); - dput(new_dentry); - if (ret) - return ret; - } - ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_dentry, 0); - return ret; -} diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c deleted file mode 100644 index 2f32539b1a37..000000000000 --- a/fs/umsdos/rdir.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * linux/fs/umsdos/rdir.c - * - * Written 1994 by Jacques Gelinas - * - * Extended MS-DOS directory pure MS-DOS handling functions - * (For directory without EMD file). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - -extern struct dentry *saved_root; -extern struct inode *pseudo_root; -extern struct dentry_operations umsdos_dentry_operations; - -struct RDIR_FILLDIR { - void *dirbuf; - filldir_t filldir; - int real_root; -}; - -static int rdir_filldir ( void *buf, - const char *name, - int name_len, - loff_t offset, - ino_t ino, - unsigned int d_type) -{ - int ret = 0; - struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR *) buf; - - if (d->real_root) { - PRINTK ((KERN_DEBUG "rdir_filldir /mn/: real root!\n")); - /* real root of a pseudo_rooted partition */ - if (name_len != UMSDOS_PSDROOT_LEN - || memcmp (name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN) != 0) { - /* So it is not the /linux directory */ - if (name_len == 2 && name[0] == '.' && name[1] == '.') { - /* Make sure the .. entry points back to the pseudo_root */ - ino = pseudo_root->i_ino; - } - ret = d->filldir (d->dirbuf, name, name_len, offset, ino, DT_UNKNOWN); - } - } else { - /* Any DOS directory */ - ret = d->filldir (d->dirbuf, name, name_len, offset, ino, DT_UNKNOWN); - } - return ret; -} - - -static int UMSDOS_rreaddir (struct file *filp, void *dirbuf, filldir_t filldir) -{ - struct inode *dir = filp->f_dentry->d_inode; - struct RDIR_FILLDIR bufk; - int ret; - - lock_kernel(); - bufk.filldir = filldir; - bufk.dirbuf = dirbuf; - bufk.real_root = pseudo_root && (dir == saved_root->d_inode); - ret = fat_readdir (filp, &bufk, rdir_filldir); - unlock_kernel(); - return ret; -} - - -/* - * Lookup into a non promoted directory. - * If the result is a directory, make sure we find out if it is - * a promoted one or not (calling umsdos_setup_dir_inode(inode)). - */ -/* #Specification: pseudo root / DOS/.. - * In the real root directory (c:\), the directory .. - * is the pseudo root (c:\linux). - */ -struct dentry *umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo) -{ - struct dentry *ret; - - if (saved_root && dir == saved_root->d_inode && !nopseudo && - dentry->d_name.len == UMSDOS_PSDROOT_LEN && - memcmp (dentry->d_name.name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN) == 0) { - /* #Specification: pseudo root / DOS/linux - * Even in the real root directory (c:\), the directory - * /linux won't show - */ - - ret = ERR_PTR(-ENOENT); - goto out; - } - - ret = msdos_lookup (dir, dentry, NULL); - if (ret) { - printk(KERN_WARNING - "umsdos_rlookup_x: %s/%s failed, ret=%ld\n", - dentry->d_parent->d_name.name, dentry->d_name.name, - PTR_ERR(ret)); - goto out; - } - if (dentry->d_inode) { - /* We must install the proper function table - * depending on whether this is an MS-DOS or - * a UMSDOS directory - */ -Printk ((KERN_DEBUG "umsdos_rlookup_x: patch_dentry_inode %s/%s\n", -dentry->d_parent->d_name.name, dentry->d_name.name)); -/* only patch if needed (because we get called even for lookup - (not only rlookup) stuff sometimes, like in umsdos_covered() */ - if (UMSDOS_I(dentry->d_inode)->i_patched == 0) - umsdos_patch_dentry_inode(dentry, 0); - - } -out: - /* always install our dentry ops ... */ - dentry->d_op = &umsdos_dentry_operations; - return ret; -} - - -struct dentry *UMSDOS_rlookup ( struct inode *dir, struct dentry *dentry, struct nameidata *nd) -{ - return umsdos_rlookup_x (dir, dentry, 0); -} - - -/* #Specification: dual mode / rmdir in a DOS directory - * In a DOS (not EMD in it) directory, we use a reverse strategy - * compared with a UMSDOS directory. We assume that a subdirectory - * of a DOS directory is also a DOS directory. This is not always - * true (umssync may be used anywhere), but makes sense. - * - * So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY - * then we check if it is a Umsdos directory. We check if it is - * really empty (only . .. and --linux-.--- in it). If it is true - * we remove the EMD and do a msdos_rmdir() again. - * - * In a Umsdos directory, we assume all subdirectories are also - * Umsdos directories, so we check the EMD file first. - */ -/* #Specification: pseudo root / rmdir /DOS - * The pseudo sub-directory /DOS can't be removed! - * This is done even if the pseudo root is not a Umsdos - * directory anymore (very unlikely), but an accident (under - * MS-DOS) is always possible. - * - * EPERM is returned. - */ -static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry) -{ - int ret, empty; - - ret = -EPERM; - if (umsdos_is_pseudodos (dir, dentry)) - goto out; - - ret = -EBUSY; - if (!d_unhashed(dentry)) - goto out; - - ret = msdos_rmdir (dir, dentry); - if (ret != -ENOTEMPTY) - goto out; - - empty = umsdos_isempty (dentry); - if (empty == 1) { - struct dentry *demd; - /* We have to remove the EMD file. */ - demd = umsdos_get_emd_dentry(dentry); - ret = PTR_ERR(demd); - if (!IS_ERR(demd)) { - ret = 0; - if (demd->d_inode) - ret = msdos_unlink (dentry->d_inode, demd); - if (!ret) - d_delete(demd); - dput(demd); - } - } - if (ret) - goto out; - - /* now retry the original ... */ - ret = msdos_rmdir (dir, dentry); - -out: - return ret; -} - -/* #Specification: dual mode / introduction - * One goal of UMSDOS is to allow a practical and simple coexistence - * between MS-DOS and Linux in a single partition. Using the EMD file - * in each directory, UMSDOS adds Unix semantics and capabilities to - * a normal DOS filesystem. To help and simplify coexistence, here is - * the logic related to the EMD file. - * - * If it is missing, then the directory is managed by the MS-DOS driver. - * The names are limited to DOS limits (8.3). No links, no device special - * and pipe and so on. - * - * If it is there, it is the directory. If it is there but empty, then - * the directory looks empty. The utility umssync allows synchronisation - * of the real DOS directory and the EMD. - * - * Whenever umssync is applied to a directory without EMD, one is - * created on the fly. The directory is promoted to full Unix semantics. - * Of course, the ls command will show exactly the same content as before - * the umssync session. - * - * It is believed that the user/admin will promote directories to Unix - * semantics as needed. - * - * The strategy to implement this is to use two function table (struct - * inode_operations). One for true UMSDOS directory and one for directory - * with missing EMD. - * - * Functions related to the DOS semantic (but aware of UMSDOS) generally - * have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate - * from the one with full UMSDOS semantics. - */ -struct file_operations umsdos_rdir_operations = -{ - .read = generic_read_dir, - .readdir = UMSDOS_rreaddir, - .ioctl = UMSDOS_ioctl_dir, -}; - -struct inode_operations umsdos_rdir_inode_operations = -{ - .create = msdos_create, - .lookup = UMSDOS_rlookup, - .unlink = msdos_unlink, - .mkdir = msdos_mkdir, - .rmdir = UMSDOS_rrmdir, - .rename = msdos_rename, - .setattr = UMSDOS_notify_change, -}; diff --git a/fs/umsdos/specs b/fs/umsdos/specs deleted file mode 100644 index 0f7d68c0aef6..000000000000 --- a/fs/umsdos/specs +++ /dev/null @@ -1,289 +0,0 @@ -/* #Specification: umsdos / readdir - * umsdos_readdir() should fill a struct dirent with - * an inode number. The cheap way to get it is to - * do a lookup in the MSDOS directory for each - * entry processed by the readdir() function. - * This is not very efficient, but very simple. The - * other way around is to maintain a copy of the inode - * number in the EMD file. This is a problem because - * this has to be maintained in sync using tricks. - * Remember that MSDOS (the OS) does not update the - * modification time (mtime) of a directory. There is - * no easy way to tell that a directory was modified - * during a DOS session and synchronise the EMD file. - */ - /* #Specification: readdir / . and .. - * The msdos filesystem manages the . and .. entry properly - * so the EMD file won't hold any info about it. - * - * In readdir, we assume that for the root directory - * the read position will be 0 for ".", 1 for "..". For - * a non root directory, the read position will be 0 for "." - * and 32 for "..". - */ - /* - * This is a trick used by the msdos file system (fs/msdos/dir.c) - * to manage . and .. for the root directory of a file system. - * Since there is no such entry in the root, fs/msdos/dir.c - * use the following: - * - * if f_pos == 0, return ".". - * if f_pos == 1, return "..". - * - * So let msdos handle it - * - * Since umsdos entries are much larger, we share the same f_pos. - * if f_pos is 0 or 1 or 32, we are clearly looking at . and - * .. - * - * As soon as we get f_pos == 2 or f_pos == 64, then back to - * 0, but this time we are reading the EMD file. - * - * Well, not so true. The problem, is that UMSDOS_REC_SIZE is - * also 64, so as soon as we read the first record in the - * EMD, we are back at offset 64. So we set the offset - * to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the - * .. entry from msdos. - * - * Now (linux 1.3), umsdos_readdir can read more than one - * entry even if we limit (umsdos_dir_once) to only one: - * It skips over hidden file. So we switch to - * UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully - * the .. entry. - */ - /* #Specification: umsdos / lookup / inode info - * After successfully reading an inode from the MSDOS - * filesystem, we use the EMD file to complete it. - * We update the following field. - * - * uid, gid, atime, ctime, mtime, mode. - * - * We rely on MSDOS for mtime. If the file - * was modified during an MSDOS session, at least - * mtime will be meaningful. We do this only for regular - * file. - * - * We don't rely on MS-DOS for mtime for directories - * because the MS-DOS date on a directory is its - * creation time (strange MSDOS behavior) which - * corresponds to none of the three Unix time stamps. - */ - /* #Specification: umsdos / conversion mode - * The msdos filesystem can do some inline conversion - * of the data of a file. It can translate silently - * from the MS-DOS text file format to the Unix one - * (CRLF -> LF) while reading, and the reverse - * while writing. This is activated using the mount - * option conv=.... - * - * This is not useful for Linux files in a promoted - * directory. It can even be harmful. For this - * reason, the binary (no conversion) mode is - * always activated. - */ - /* #Specification: umsdos / conversion mode / todo - * A flag could be added to file and directories - * forcing an automatic conversion mode (as - * done with the msdos filesystem). - * - * This flag could be setup on a directory basis - * (instead of file) and all files in it would - * logically inherit it. If the conversion mode - * is active (conv=) then the i_binary flag would - * be left untouched in those directories. - * - * It was proposed that the sticky bit be used to set - * this. A problem with that is that new files would - * be written incorrectly. The other problem is that - * the sticky bit has a meaning for directories. So - * another bit should be used (there is some space - * in the EMD file for it) and a special utility - * would be used to assign the flag to a directory). - * I don't think it is useful to assign this flag - * on a single file. - */ - * #Specification: weakness / rename - * There is a case where UMSDOS rename has a different behavior - * than a normal Unix file system. Renaming an open file across - * directory boundary does not work. Renaming an open file within - * a directory does work, however. - * - * The problem may is in Linux VFS driver for msdos. - * I believe this is not a bug but a design feature, because - * an inode number represents some sort of directory address - * in the MSDOS directory structure, so moving the file into - * another directory does not preserve the inode number. - */ -/* #Specification: rename / new name exist - * If the destination name already exists, it will - * silently be removed. EXT2 does it this way - * and this is the spec of SunOS. So does UMSDOS. - * - * If the destination is an empty directory it will - * also be removed. - */ -/* #Specification: rename / new name exist / possible flaw - * The code to handle the deletion of the target (file - * and directory) use to be in umsdos_rename_f, surrounded - * by proper directory locking. This was ensuring that only - * one process could achieve a rename (modification) operation - * in the source and destination directory. This was also - * ensuring the operation was "atomic". - * - * This has been changed because this was creating a - * stack overflow (the stack is only 4 kB) in the kernel. To avoid - * the code doing the deletion of the target (if exist) has - * been moved to a upper layer. umsdos_rename_f is tried - * once and if it fails with EEXIST, the target is removed - * and umsdos_rename_f is done again. - * - * This makes the code cleaner and may solve a - * deadlock problem one tester was experiencing. - * - * The point is to mention that possibly, the semantic of - * "rename" may be wrong. Anyone dare to check that :-) - * Be aware that IF it is wrong, to produce the problem you - * will need two process trying to rename a file to the - * same target at the same time. Again, I am not sure it - * is a problem at all. - */ - -/* #Specification: hard link / strategy - * Hard links are difficult to implement on top of an MS-DOS FAT file - * system. Unlike Unix file systems, there are no inodes. A directory - * entry holds the functionality of the inode and the entry. - * - * We will used the same strategy as a normal Unix file system - * (with inodes) except we will do it symbolically (using paths). - * - * Because anything can happen during a DOS session (defragment, - * directory sorting, etc.), we can't rely on an MS-DOS pseudo - * inode number to record the link. For this reason, the link - * will be done using hidden symbolic links. The following - * scenario illustrates how it works. - * - * Given a file /foo/file - * - * # - * ln /foo/file /tmp/file2 - * - * become internally - * - * mv /foo/file /foo/-LINK1 - * ln -s /foo/-LINK1 /foo/file - * ln -s /foo/-LINK1 /tmp/file2 - * # - * - * Using this strategy, we can operate on /foo/file or /foo/file2. - * We can remove one and keep the other, like a normal Unix hard link. - * We can rename /foo/file or /tmp/file2 independently. - * - * The entry -LINK1 will be hidden. It will hold a link count. - * When all link are erased, the hidden file is erased too. - */ - -/* #Specification: weakness / hard link - * The strategy for hard link introduces a side effect that - * may or may not be acceptable. Here is the sequence - * - * # - * mkdir subdir1 - * touch subdir1/file - * mkdir subdir2 - * ln subdir1/file subdir2/file - * rm subdir1/file - * rmdir subdir1 - * rmdir: subdir1: Directory not empty - * # - * - * This happen because there is an invisible file (--link) in - * subdir1 which is referenced by subdir2/file. - * - * Any idea ? - */ -/* #Specification: weakness / hard link / rename directory - * Another weakness of hard link come from the fact that - * it is based on hidden symbolic links. Here is an example. - * - * # - * mkdir /subdir1 - * touch /subdir1/file - * mkdir /subdir2 - * ln /subdir1/file subdir2/file - * mv /subdir1 subdir3 - * ls -l /subdir2/file - * # - * - * Since /subdir2/file is a hidden symbolic link - * to /subdir1/..hlinkNNN, accessing it will fail since - * /subdir1 does not exist anymore (has been renamed). - */ -/* #Specification: hard link / directory - * A hard link can't be made on a directory. EPERM is returned - * in this case. - */ -/* #Specification: hard link / first hard link - * The first time a hard link is done on a file, this - * file must be renamed and hidden. Then an internal - * symbolic link must be done on the hidden file. - * - * The second link is done after on this hidden file. - * - * It is expected that the Linux MSDOS file system - * keeps the same pseudo inode when a rename operation - * is done on a file in the same directory. - */ -/* #Specification: function name / convention - * A simple convention for function names has been used in - * the UMSDOS filesystem. First, all functions use the prefix - * umsdos_ to avoid name clashes with other parts of the kernel. - * - * Standard VFS entry points use the prefix UMSDOS (upper case) - * so it's easier to tell them apart. - * N.B. (FIXME) PTW, the order and contents of this struct changed. - */ - -/* #Specification: mount / options - * Umsdos run on top of msdos. Currently, it supports no - * mount option, but happily pass all option received to - * the msdos driver. I am not sure if all msdos mount option - * make sense with Umsdos. Here are at least those who - * are useful. - * uid= - * gid= - * - * These options affect the operation of umsdos in directories - * which do not have an EMD file. They behave like normal - * msdos directory, with all limitation of msdos. - */ - -/* #Specification: pseudo root / mount - * When a umsdos fs is mounted, a special handling is done - * if it is the root partition. We check for the presence - * of the file /linux/etc/init or /linux/etc/rc or - * /linux/sbin/init. If one is there, we do a chroot("/linux"). - * - * We check both because (see init/main.c) the kernel - * try to exec init at different place and if it fails - * it tries /bin/sh /etc/rc. To be consistent with - * init/main.c, many more test would have to be done - * to locate init. Any complain ? - * - * The chroot is done manually in init/main.c but the - * info (the inode) is located at mount time and store - * in a global variable (pseudo_root) which is used at - * different place in the umsdos driver. There is no - * need to store this variable elsewhere because it - * will always be one, not one per mount. - * - * This feature allows the installation - * of a linux system within a DOS system in a subdirectory. - * - * A user may install its linux stuff in c:\linux - * avoiding any clash with existing DOS file and subdirectory. - * When linux boots, it hides this fact, showing a normal - * root directory with /etc /bin /tmp ... - * - * The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h - * in the macro UMSDOS_PSDROOT_NAME. - */ diff --git a/include/linux/umsdos_fs.h b/include/linux/umsdos_fs.h deleted file mode 100644 index 67c25693db66..000000000000 --- a/include/linux/umsdos_fs.h +++ /dev/null @@ -1,182 +0,0 @@ -#ifndef LINUX_UMSDOS_FS_H -#define LINUX_UMSDOS_FS_H - - -/*#define UMS_DEBUG 1 // define for check_* functions */ -/*#define UMSDOS_DEBUG 1*/ -#define UMSDOS_PARANOIA 1 - -#define UMSDOS_VERSION 0 -#define UMSDOS_RELEASE 4 - -#define UMSDOS_ROOT_INO 1 - -/* This is the file acting as a directory extension */ -#define UMSDOS_EMD_FILE "--linux-.---" -#define UMSDOS_EMD_NAMELEN 12 -#define UMSDOS_PSDROOT_NAME "linux" -#define UMSDOS_PSDROOT_LEN 5 - -#ifndef _LINUX_TYPES_H -#include -#endif -#ifndef _LINUX_LIMITS_H -#include -#endif -#ifndef _LINUX_DIRENT_H -#include -#endif -#ifndef _LINUX_IOCTL_H -#include -#endif - - -#ifdef __KERNEL__ -/* #Specification: convention / PRINTK Printk and printk - * Here is the convention for the use of printk inside fs/umsdos - * - * printk carry important message (error or status). - * Printk is for debugging (it is a macro defined at the beginning of - * most source. - * PRINTK is a nulled Printk macro. - * - * This convention makes the source easier to read, and Printk easier - * to shut off. - */ -# define PRINTK(x) -# ifdef UMSDOS_DEBUG -# define Printk(x) printk x -# else -# define Printk(x) -# endif -#endif /* __KERNEL__ */ - - -struct umsdos_fake_info { - char fname[13]; - int len; -}; - -#define UMSDOS_MAXNAME 220 -/* This structure is 256 bytes large, depending on the name, only part */ -/* of it is written to disk */ -/* nice though it would be, I can't change this and preserve backward compatibility */ -struct umsdos_dirent { - unsigned char name_len; /* if == 0, then this entry is not used */ - unsigned char flags; /* UMSDOS_xxxx */ - unsigned short nlink; /* How many hard links point to this entry */ - __kernel_uid_t uid; /* Owner user id */ - __kernel_gid_t gid; /* Group id */ - time_t atime; /* Access time */ - time_t mtime; /* Last modification time */ - time_t ctime; /* Creation time */ - unsigned short rdev; /* major and minor of a device special file */ - umode_t mode; /* Standard UNIX permissions bits + type of */ - char spare[12]; /* unused bytes for future extensions */ - /* file, see linux/stat.h */ - char name[UMSDOS_MAXNAME]; /* Not '\0' terminated */ - /* but '\0' padded, so it will allow */ - /* for adding news fields in this record */ - /* by reducing the size of name[] */ -}; - -#define UMSDOS_HIDDEN 1 /* Never show this entry in directory search */ -#define UMSDOS_HLINK 2 /* It is a (pseudo) hard link */ - -/* #Specification: EMD file / record size - * Entry are 64 bytes wide in the EMD file. It allows for a 30 characters - * name. If a name is longer, contiguous entries are allocated. So a - * umsdos_dirent may span multiple records. - */ - -#define UMSDOS_REC_SIZE 64 - -/* Translation between MSDOS name and UMSDOS name */ - -struct umsdos_info { - int msdos_reject; /* Tell if the file name is invalid for MSDOS */ - /* See umsdos_parse */ - struct umsdos_fake_info fake; - struct umsdos_dirent entry; - off_t f_pos; /* offset of the entry in the EMD file - * or offset where the entry may be store - * if it is a new entry - */ - int recsize; /* Record size needed to store entry */ -}; - -/* Definitions for ioctl (number randomly chosen) - * The next ioctl commands operate only on the DOS directory - * The file umsdos_progs/umsdosio.c contain a string table - * based on the order of those definition. Keep it in sync - */ -#define UMSDOS_READDIR_DOS _IO(0x04,210) /* Do a readdir of the DOS directory */ -#define UMSDOS_UNLINK_DOS _IO(0x04,211) /* Erase in the DOS directory only */ -#define UMSDOS_RMDIR_DOS _IO(0x04,212) /* rmdir in the DOS directory only */ -#define UMSDOS_STAT_DOS _IO(0x04,213) /* Get info about a file */ - -/* The next ioctl commands operate only on the EMD file */ -#define UMSDOS_CREAT_EMD _IO(0x04,214) /* Create a file */ -#define UMSDOS_UNLINK_EMD _IO(0x04,215) /* unlink (rmdir) a file */ -#define UMSDOS_READDIR_EMD _IO(0x04,216) /* read the EMD file only. */ -#define UMSDOS_GETVERSION _IO(0x04,217) /* Get the release number of UMSDOS */ -#define UMSDOS_INIT_EMD _IO(0x04,218) /* Create the EMD file if not there */ -#define UMSDOS_DOS_SETUP _IO(0x04,219) /* Set the defaults of the MS-DOS driver. */ - -#define UMSDOS_RENAME_DOS _IO(0x04,220) /* rename a file/directory in the DOS - * directory only */ -struct umsdos_ioctl { - struct dirent dos_dirent; - struct umsdos_dirent umsdos_dirent; - /* The following structure is used to exchange some data with - * utilities (umsdos_progs/util/umsdosio.c). The first releases - * were using struct stat from "sys/stat.h". This was causing - * some problem for cross compilation of the kernel. - * Since I am not really using the structure stat, but only - * some fields of it, I have decided to replicate the structure - * here for compatibility with the binaries out there. - * FIXME PTW 1998, this has probably changed - */ - - struct { - unsigned long st_dev; - ino_t st_ino; /* used */ - umode_t st_mode; /* used */ - nlink_t st_nlink; - __kernel_uid_t st_uid; - __kernel_gid_t st_gid; - unsigned long st_rdev; - off_t st_size; /* used */ - unsigned long st_blksize; - unsigned long st_blocks; - time_t st_atime; /* used */ - unsigned long __unused1; - time_t st_mtime; /* used */ - unsigned long __unused2; - time_t st_ctime; /* used */ - unsigned long __unused3; - uid_t st_uid32; - gid_t st_gid32; - } stat; - char version, release; -}; - -/* Different macros to access struct umsdos_dirent */ -#define EDM_ENTRY_ISUSED(e) ((e)->name_len!=0) - -#ifdef __KERNEL__ - -#ifndef LINUX_FS_H -#include -#endif - -extern struct inode_operations umsdos_dir_inode_operations; -extern struct inode_operations umsdos_rdir_inode_operations; -extern struct file_operations umsdos_dir_operations; -extern struct file_operations umsdos_rdir_operations; - -#include - -#endif /* __KERNEL__ */ - -#endif diff --git a/include/linux/umsdos_fs.p b/include/linux/umsdos_fs.p deleted file mode 100644 index 1c284c5a7aec..000000000000 --- a/include/linux/umsdos_fs.p +++ /dev/null @@ -1,100 +0,0 @@ -/* check.c 23/01/95 03.38.30 */ -void check_page_tables (void); - -/* dir.c 22/06/95 00.22.12 */ -int dummy_dir_read ( struct file *filp, - char *buf, - size_t size, - loff_t *count); -char * umsdos_d_path(struct dentry *, char *, int); -void umsdos_lookup_patch_new(struct dentry *, struct umsdos_info *); -int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry); -struct dentry *umsdos_lookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo); -struct dentry *UMSDOS_lookup(struct inode *, struct dentry *, struct nameidata *); -struct dentry *umsdos_lookup_dentry(struct dentry *, char *, int, int); -struct dentry *umsdos_covered(struct dentry *, char *, int); - -struct dentry *umsdos_solve_hlink (struct dentry *hlink); - -/* emd.c 22/06/95 00.22.04 */ -struct dentry *umsdos_get_emd_dentry(struct dentry *); -int umsdos_have_emd(struct dentry *); -int umsdos_make_emd(struct dentry *); -int umsdos_emd_dir_readentry (struct dentry *, loff_t *, struct umsdos_dirent *); -int umsdos_newentry (struct dentry *, struct umsdos_info *); -int umsdos_newhidden (struct dentry *, struct umsdos_info *); -int umsdos_delentry (struct dentry *, struct umsdos_info *, int); -int umsdos_findentry (struct dentry *, struct umsdos_info *, int); -int umsdos_isempty (struct dentry *); -int umsdos_writeentry (struct dentry *, struct umsdos_info *, int); - -/* file.c 25/01/95 02.25.38 */ - -/* inode.c 12/06/95 09.49.40 */ -void fill_new_filp (struct file *filp, struct dentry *dentry); -void UMSDOS_read_inode (struct inode *); -void UMSDOS_write_inode (struct inode *, int); -int UMSDOS_notify_change (struct dentry *, struct iattr *attr); -int umsdos_notify_change_locked(struct dentry *, struct iattr *attr); -void UMSDOS_put_inode (struct inode *); -int UMSDOS_statfs (struct super_block *, struct statfs *); -struct super_block *UMSDOS_read_super (struct super_block *, void *, int); -void UMSDOS_put_super (struct super_block *); - -void umsdos_setup_dir(struct dentry *); -void umsdos_set_dirinfo_new(struct dentry *, off_t); -void umsdos_patch_dentry_inode (struct dentry *, off_t); -int umsdos_get_dirowner (struct inode *inode, struct inode **result); - -/* ioctl.c 22/06/95 00.22.08 */ -int UMSDOS_ioctl_dir (struct inode *dir, - struct file *filp, - unsigned int cmd, - unsigned long data); - -/* mangle.c 25/01/95 02.25.38 */ -void umsdos_manglename (struct umsdos_info *info); -int umsdos_evalrecsize (int len); -int umsdos_parse (const char *name,int len, struct umsdos_info *info); - -/* namei.c 25/01/95 02.25.38 */ -void umsdos_lockcreate (struct inode *dir); -void umsdos_startlookup (struct inode *dir); -void umsdos_unlockcreate (struct inode *dir); -void umsdos_endlookup (struct inode *dir); - -int umsdos_readlink_x ( struct dentry *dentry, - char *buffer, - int bufsiz); -int UMSDOS_symlink (struct inode *dir, - struct dentry *dentry, - const char *symname); -int UMSDOS_link (struct dentry *olddentry, - struct inode *dir, - struct dentry *dentry); -int UMSDOS_create (struct inode *dir, - struct dentry *dentry, - int mode); - -int UMSDOS_mkdir (struct inode *dir, - struct dentry *dentry, - int mode); -int UMSDOS_mknod (struct inode *dir, - struct dentry *dentry, - int mode, - dev_t rdev); -int UMSDOS_rmdir (struct inode *dir,struct dentry *dentry); -int UMSDOS_unlink (struct inode *dir, struct dentry *dentry); -int UMSDOS_rename (struct inode *old_dir, - struct dentry *old_dentry, - struct inode *new_dir, - struct dentry *new_dentry); - -/* rdir.c 22/03/95 03.31.42 */ -struct dentry *umsdos_rlookup_x (struct inode *dir, struct dentry *dentry, int nopseudo); -struct dentry *UMSDOS_rlookup (struct inode *dir, struct dentry *dentry, struct nameidata *nd); - -static inline struct umsdos_inode_info *UMSDOS_I(struct inode *inode) -{ - return &inode->u.umsdos_i; -} diff --git a/include/linux/umsdos_fs_i.h b/include/linux/umsdos_fs_i.h deleted file mode 100644 index f4c992b44cd2..000000000000 --- a/include/linux/umsdos_fs_i.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef UMSDOS_FS_I_H -#define UMSDOS_FS_I_H - -#ifndef _LINUX_TYPES_H -#include -#endif - -#include -#include - -/* #Specification: strategy / in memory inode - * Here is the information specific to the inode of the UMSDOS file - * system. This information is added to the end of the standard struct - * inode. Each file system has its own extension to struct inode, - * so do the umsdos file system. - * - * The strategy is to have the umsdos_inode_info as a superset of - * the msdos_inode_info, since most of the time the job is done - * by the msdos fs code. - * - * So we duplicate the msdos_inode_info, and add our own info at the - * end. - * - * The offset in this EMD file of the entry: pos - * - * For directory, we have dir_locking_info to help synchronise - * file creation and file lookup. See also msdos_fs_i.h for more - * information about msdos_inode_info. - * - * Special file and fifo do have an inode which correspond to an - * empty MSDOS file. - * - * symlink are processed mostly like regular file. The content is the - * link. - * - * The UMSDOS specific extension is placed after the union. - */ - -struct dir_locking_info { - wait_queue_head_t p; - short int looking; /* How many process doing a lookup */ - short int creating; /* Is there any creation going on here - * Only one at a time, although one - * may recursively lock, so it is a counter - */ - long pid; /* pid of the process owning the creation - * lock */ -}; - -struct umsdos_inode_info { - struct msdos_inode_info msdos_info; - struct dir_locking_info dir_info; - int i_patched; /* Inode has been patched */ - int i_is_hlink; /* Resolved hardlink inode? */ - off_t pos; /* Entry offset in the emd_owner file */ -}; - -#endif -- cgit v1.2.3 From eefe1116eb1798bfc2e92dcbc190df0392197bd9 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 10 Jan 2005 17:22:40 -0800 Subject: [PATCH] drivers/char/: misc cleanups below are as requested my drivers/char/ cleanups in one big patch for better merging. Each of the patches included was already sent three times without any objections to linux-kernel. The n_tty.c patch is Approved-by: Alan Cox The patch below makes changes under drivers/char/ including the following: - make needlessly global code static - remove completely unused code Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/esp.c | 2 +- drivers/char/genrtc.c | 2 +- drivers/char/ip2/fip_firm.h | 2 +- drivers/char/ip2/i2cmd.c | 59 +------- drivers/char/ip2/i2cmd.h | 17 --- drivers/char/ip2/i2lib.c | 2 +- drivers/char/ip2main.c | 5 +- drivers/char/keyboard.c | 20 +-- drivers/char/lp.c | 4 +- drivers/char/n_tty.c | 4 +- drivers/char/pcmcia/synclink_cs.c | 24 +-- drivers/char/pty.c | 2 +- drivers/char/synclink.c | 311 ++++++++++++++++++-------------------- drivers/char/tipar.c | 4 +- drivers/char/toshiba.c | 2 +- drivers/char/tty_io.c | 28 +--- drivers/char/tty_ioctl.c | 2 +- include/linux/lp.h | 6 - 18 files changed, 187 insertions(+), 309 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 62f8e3087fe6..fb681990a84d 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -2401,7 +2401,7 @@ static struct tty_operations esp_ops = { /* * The serial driver boot-time initialization code! */ -int __init espserial_init(void) +static int __init espserial_init(void) { int i, offset; struct esp_struct * info; diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c index fc02f72f013b..d3a2bc36129b 100644 --- a/drivers/char/genrtc.c +++ b/drivers/char/genrtc.c @@ -83,7 +83,7 @@ static unsigned char days_in_mo[] = static int irq_active; #ifdef CONFIG_GEN_RTC_X -struct work_struct genrtc_task; +static struct work_struct genrtc_task; static struct timer_list timer_task; static unsigned int oldsecs; diff --git a/drivers/char/ip2/fip_firm.h b/drivers/char/ip2/fip_firm.h index f118123ea912..4c525fa4929f 100644 --- a/drivers/char/ip2/fip_firm.h +++ b/drivers/char/ip2/fip_firm.h @@ -1,7 +1,7 @@ /* fip_firm.h - Intelliport II loadware */ /* -31232 bytes read from ff.lod */ -unsigned char fip_firm[] __initdata = { +static unsigned char fip_firm[] __initdata = { 0x3C,0x42,0x37,0x18,0x02,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x57,0x65,0x64,0x20,0x44,0x65,0x63,0x20,0x30,0x31,0x20,0x31,0x32,0x3A,0x32,0x34, 0x3A,0x33,0x30,0x20,0x31,0x39,0x39,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, diff --git a/drivers/char/ip2/i2cmd.c b/drivers/char/ip2/i2cmd.c index 77fd8543efc3..fd299d6c42ac 100644 --- a/drivers/char/ip2/i2cmd.c +++ b/drivers/char/ip2/i2cmd.c @@ -88,7 +88,7 @@ static UCHAR ct36[] = { 2, BTH, 0x24,0 }; // SETERRMODE //static UCHAR ct37[]={ 5, BYP|VIP, 0x25,0,0,0,0 }; // FLOW PACKET // Back to normal -static UCHAR ct38[] = {11, BTH|VAR, 0x26,0,0,0,0,0,0,0,0,0,0 }; // DEF KEY SEQ +//static UCHAR ct38[] = {11, BTH|VAR, 0x26,0,0,0,0,0,0,0,0,0,0 }; // DEF KEY SEQ //static UCHAR ct39[]={ 3, BTH|END, 0x27,0,0 }; // OPOSTON //static UCHAR ct40[]={ 1, BTH|END, 0x28 }; // OPOSTOFF static UCHAR ct41[] = { 1, BYP, 0x29 }; // RESUME @@ -103,7 +103,7 @@ static UCHAR ct47[] = { 7, BTH, 0x2F,0,0,0,0,0,0 }; // UNIX FLAGS //static UCHAR ct50[]={ 1, BTH, 0x32 }; // DTRFLOWENAB //static UCHAR ct51[]={ 1, BTH, 0x33 }; // DTRFLOWDSAB //static UCHAR ct52[]={ 1, BTH, 0x34 }; // BAUDTABRESET -static UCHAR ct53[] = { 3, BTH, 0x35,0,0 }; // BAUDREMAP +//static UCHAR ct53[] = { 3, BTH, 0x35,0,0 }; // BAUDREMAP static UCHAR ct54[] = { 3, BTH, 0x36,0,0 }; // CUSTOMBAUD1 static UCHAR ct55[] = { 3, BTH, 0x37,0,0 }; // CUSTOMBAUD2 static UCHAR ct56[] = { 2, BTH|END, 0x38,0 }; // PAUSE @@ -151,40 +151,6 @@ static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW //* Code * //******** -//****************************************************************************** -// Function: i2cmdSetSeq(type, size, string) -// Parameters: type - sequence number -// size - length of sequence -// string - substitution string -// -// Returns: Pointer to command structure -// -// Description: -// -// This routine sets the parameters of command 38 Define Hot Key sequence (alias -// "special receive sequence"). Returns a pointer to the structure. Endeavours -// to be bullet-proof in that the sequence number is forced in range, and any -// out-of-range sizes are forced to zero. -//****************************************************************************** -cmdSyntaxPtr -i2cmdSetSeq(unsigned char type, unsigned char size, unsigned char *string) -{ - cmdSyntaxPtr pCM = (cmdSyntaxPtr) ct38; - unsigned char *pc; - - pCM->cmd[1] = ((type > 0xf) ? 0xf : type); // Sequence number - size = ((size > 0x8) ? 0 : size); // size - pCM->cmd[2] = size; - pCM->length = 3 + size; // UPDATES THE LENGTH! - - pc = &(pCM->cmd[3]); - - while(size--) { - *pc++ = *string++; - } - return pCM; -} - //****************************************************************************** // Function: i2cmdUnixFlags(iflag, cflag, lflag) // Parameters: Unix tty flags @@ -210,27 +176,6 @@ i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag) return pCM; } -//****************************************************************************** -// Function: i2cmdBaudRemap(dest,src) -// Parameters: ? -// -// Returns: Pointer to command structure -// -// Description: -// -// This routine sets the parameters of command 53 and returns a pointer to the -// appropriate structure. -//****************************************************************************** -cmdSyntaxPtr -i2cmdBaudRemap(unsigned char dest, unsigned char src) -{ - cmdSyntaxPtr pCM = (cmdSyntaxPtr) ct53; - - pCM->cmd[1] = dest; - pCM->cmd[2] = src; - return pCM; -} - //****************************************************************************** // Function: i2cmdBaudDef(which, rate) // Parameters: ? diff --git a/drivers/char/ip2/i2cmd.h b/drivers/char/ip2/i2cmd.h index 83475167f491..c41728a85710 100644 --- a/drivers/char/ip2/i2cmd.h +++ b/drivers/char/ip2/i2cmd.h @@ -71,9 +71,7 @@ typedef struct _cmdSyntax // there is more than one parameter to assign, we must use a function rather // than a macro (used usually). // -extern cmdSyntaxPtr i2cmdSetSeq(UCHAR seqno, UCHAR size, UCHAR *string); extern cmdSyntaxPtr i2cmdUnixFlags(USHORT iflag,USHORT cflag,USHORT lflag); -extern cmdSyntaxPtr i2cmdBaudRemap(UCHAR dest, UCHAR src); extern cmdSyntaxPtr i2cmdBaudDef(int which, USHORT rate); // Declarations for the global arrays used to bear the commands and their @@ -397,14 +395,6 @@ static UCHAR cc02[]; // library code in response to data movement and shouldn't ever be sent by the // user code. See i2pack.h and the body of i2lib.c for details. -// COMMAND 38: Define the hot-key sequence -// seqno: sequence number 0-15 -// size: number of characters in sequence (1-8) -// string: pointer to the characters -// (if size == 0, "undefines" this sequence -// -#define CMD_SET_SEQ(seqno,size,string) i2cmdSetSeq(seqno,size,string) - // Enable on-board post-processing, using options given in oflag argument. // Formerly, this command was automatically preceded by a CMD_OPOST_OFF command // because the loadware does not permit sending back-to-back CMD_OPOST_ON @@ -458,13 +448,6 @@ static UCHAR cc02[]; #define CMD_DTRFL_DSAB (cmdSyntaxPtr)(ct51) // Disable DTR flow control #define CMD_BAUD_RESET (cmdSyntaxPtr)(ct52) // Reset baudrate table -// COMMAND 53: Remap baud rate table -// dest = index of table entry to be changed -// src = index value to substitute. -// at default mapping table is f(x) = x -// -#define CMD_BAUD_REMAP(dest,src) i2cmdBaudRemap(dest,src) - // COMMAND 54: Define custom rate #1 // rate = (short) 1/10 of the desired baud rate // diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c index a886e954cae9..82c5f30375ac 100644 --- a/drivers/char/ip2/i2lib.c +++ b/drivers/char/ip2/i2lib.c @@ -141,7 +141,7 @@ fatality(i2eBordStrPtr pB ) //* Code * //******** -inline int +static inline int i2Validate ( i2ChanStrPtr pCh ) { //ip2trace(pCh->port_index, ITRC_VERIFY,ITRC_ENTER,2,pCh->validity, diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c index 3d3ae6856bbd..fca9a978fb73 100644 --- a/drivers/char/ip2main.c +++ b/drivers/char/ip2main.c @@ -138,7 +138,7 @@ #include static int ip2_read_procmem(char *, char **, off_t, int); -int ip2_read_proc(char *, char **, off_t, int, int *, void * ); +static int ip2_read_proc(char *, char **, off_t, int, int *, void * ); /********************/ /* Type Definitions */ @@ -202,7 +202,6 @@ static void do_status(void *p); static void ip2_wait_until_sent(PTTY,int); static void set_params (i2ChanStrPtr, struct termios *); -static int set_modem_info(i2ChanStrPtr, unsigned int, unsigned int *); static int get_serial_info(i2ChanStrPtr, struct serial_struct __user *); static int set_serial_info(i2ChanStrPtr, struct serial_struct __user *); @@ -3097,7 +3096,7 @@ ip2_read_procmem(char *buf, char **start, off_t offset, int len) * different sources including ip2mkdev.c and a couple of other drivers. * The bugs are all mine. :-) =mhw= */ -int ip2_read_proc(char *page, char **start, off_t off, +static int ip2_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { int i, j, box; diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 7c943edc7dcc..fae2ab6d9dc3 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -330,7 +330,7 @@ static void applkey(struct vc_data *vc, int key, char mode) * in utf-8 already. UTF-8 is defined for words of up to 31 bits, * but we need only 16 bits here */ -void to_utf8(struct vc_data *vc, ushort c) +static void to_utf8(struct vc_data *vc, ushort c) { if (c < 0x80) /* 0******* */ @@ -392,7 +392,7 @@ void compute_shiftstate(void) * Otherwise, conclude that DIACR was not combining after all, * queue it and return CH. */ -unsigned char handle_diacr(struct vc_data *vc, unsigned char ch) +static unsigned char handle_diacr(struct vc_data *vc, unsigned char ch) { int d = diacr; int i; @@ -853,18 +853,6 @@ void setledstate(struct kbd_struct *kbd, unsigned int led) set_leds(); } -void register_leds(struct kbd_struct *kbd, unsigned int led, - unsigned int *addr, unsigned int mask) -{ - if (led < 3) { - ledptrs[led].addr = addr; - ledptrs[led].mask = mask; - ledptrs[led].valid = 1; - kbd->ledmode = LED_SHOW_MEM; - } else - kbd->ledmode = LED_SHOW_FLAGS; -} - static inline unsigned char getleds(void) { struct kbd_struct *kbd = kbd_table + fg_console; @@ -925,7 +913,7 @@ DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); /* * This allows a newly plugged keyboard to pick the LED state. */ -void kbd_refresh_leds(struct input_handle *handle) +static void kbd_refresh_leds(struct input_handle *handle) { unsigned char leds = ledstate; @@ -1027,7 +1015,7 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char u } #endif -void kbd_rawcode(unsigned char data) +static void kbd_rawcode(unsigned char data) { struct vc_data *vc = vc_cons[fg_console].d; kbd = kbd_table + fg_console; diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 093f79828fca..92a54cb659d6 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -142,7 +142,7 @@ /* ROUND_UP macro from fs/select.c */ #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) -struct lp_struct lp_table[LP_NO]; +static struct lp_struct lp_table[LP_NO]; static unsigned int lp_count = 0; static struct class_simple *lp_class; @@ -867,7 +867,7 @@ static struct parport_driver lp_driver = { .detach = lp_detach, }; -int __init lp_init (void) +static int __init lp_init (void) { int i, err = 0; diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index a29dffd9408e..4280394442f7 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -152,7 +152,7 @@ static void reset_buffer_flags(struct tty_struct *tty) * lock_kernel() still. */ -void n_tty_flush_buffer(struct tty_struct * tty) +static void n_tty_flush_buffer(struct tty_struct * tty) { /* clear everything and unthrottle the driver */ reset_buffer_flags(tty); @@ -174,7 +174,7 @@ void n_tty_flush_buffer(struct tty_struct * tty) * at this instant in time. */ -ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) +static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) { unsigned long flags; ssize_t n = 0; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index e331fc0ce3c5..234af616f220 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -923,7 +923,7 @@ static void tx_release(struct tty_struct *tty) /* Return next bottom half action to perform. * or 0 if nothing to do. */ -int bh_action(MGSLPC_INFO *info) +static int bh_action(MGSLPC_INFO *info) { unsigned long flags; int rc = 0; @@ -1017,7 +1017,7 @@ void bh_status(MGSLPC_INFO *info) } /* eom: non-zero = end of frame */ -void rx_ready_hdlc(MGSLPC_INFO *info, int eom) +static void rx_ready_hdlc(MGSLPC_INFO *info, int eom) { unsigned char data[2]; unsigned char fifo_count, read_count, i; @@ -1079,7 +1079,7 @@ void rx_ready_hdlc(MGSLPC_INFO *info, int eom) issue_command(info, CHA, CMD_RXFIFO); } -void rx_ready_async(MGSLPC_INFO *info, int tcd) +static void rx_ready_async(MGSLPC_INFO *info, int tcd) { unsigned char data, status; int fifo_count; @@ -1153,7 +1153,7 @@ void rx_ready_async(MGSLPC_INFO *info, int tcd) } -void tx_done(MGSLPC_INFO *info) +static void tx_done(MGSLPC_INFO *info) { if (!info->tx_active) return; @@ -1190,7 +1190,7 @@ void tx_done(MGSLPC_INFO *info) } } -void tx_ready(MGSLPC_INFO *info) +static void tx_ready(MGSLPC_INFO *info) { unsigned char fifo_count = 32; int c; @@ -1239,7 +1239,7 @@ void tx_ready(MGSLPC_INFO *info) } } -void cts_change(MGSLPC_INFO *info) +static void cts_change(MGSLPC_INFO *info) { get_signals(info); if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) @@ -1276,7 +1276,7 @@ void cts_change(MGSLPC_INFO *info) info->pending_bh |= BH_STATUS; } -void dcd_change(MGSLPC_INFO *info) +static void dcd_change(MGSLPC_INFO *info) { get_signals(info); if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) @@ -1310,7 +1310,7 @@ void dcd_change(MGSLPC_INFO *info) info->pending_bh |= BH_STATUS; } -void dsr_change(MGSLPC_INFO *info) +static void dsr_change(MGSLPC_INFO *info) { get_signals(info); if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) @@ -1325,7 +1325,7 @@ void dsr_change(MGSLPC_INFO *info) info->pending_bh |= BH_STATUS; } -void ri_change(MGSLPC_INFO *info) +static void ri_change(MGSLPC_INFO *info) { get_signals(info); if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) @@ -2955,7 +2955,7 @@ static inline int line_info(char *buf, MGSLPC_INFO *info) /* Called to print information about devices */ -int mgslpc_read_proc(char *page, char **start, off_t off, int count, +static int mgslpc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0, l; @@ -3218,7 +3218,7 @@ static void __exit synclink_cs_exit(void) module_init(synclink_cs_init); module_exit(synclink_cs_exit); -void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned int rate) +static void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned int rate) { unsigned int M, N; unsigned char val; @@ -3254,7 +3254,7 @@ void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned int rate /* Enabled the AUX clock output at the specified frequency. */ -void enable_auxclk(MGSLPC_INFO *info) +static void enable_auxclk(MGSLPC_INFO *info) { unsigned char val; diff --git a/drivers/char/pty.c b/drivers/char/pty.c index a47386427eb2..22e6caadcddf 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -35,7 +35,7 @@ /* These are global because they are accessed in tty_io.c */ #ifdef CONFIG_UNIX98_PTYS struct tty_driver *ptm_driver; -struct tty_driver *pts_driver; +static struct tty_driver *pts_driver; #endif static void pty_close(struct tty_struct * tty, struct file * filp) diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index a23342724582..37c8bea8e2b0 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -53,7 +53,6 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) #if defined(__i386__) # define BREAKPOINT() asm(" int $3"); #else @@ -118,7 +117,7 @@ #define RCLRVALUE 0xffff -MGSL_PARAMS default_params = { +static MGSL_PARAMS default_params = { MGSL_MODE_HDLC, /* unsigned long mode */ 0, /* unsigned char loopback; */ HDLC_FLAG_UNDERRUN_ABORT15, /* unsigned short flags; */ @@ -679,13 +678,13 @@ void usc_ClearIrqPendingBits( struct mgsl_struct *info, u16 IrqMask ); #define usc_EnableReceiver(a,b) \ usc_OutReg( (a), RMR, (u16)((usc_InReg((a),RMR) & 0xfffc) | (b)) ) -u16 usc_InDmaReg( struct mgsl_struct *info, u16 Port ); -void usc_OutDmaReg( struct mgsl_struct *info, u16 Port, u16 Value ); -void usc_DmaCmd( struct mgsl_struct *info, u16 Cmd ); +static u16 usc_InDmaReg( struct mgsl_struct *info, u16 Port ); +static void usc_OutDmaReg( struct mgsl_struct *info, u16 Port, u16 Value ); +static void usc_DmaCmd( struct mgsl_struct *info, u16 Cmd ); -u16 usc_InReg( struct mgsl_struct *info, u16 Port ); -void usc_OutReg( struct mgsl_struct *info, u16 Port, u16 Value ); -void usc_RTCmd( struct mgsl_struct *info, u16 Cmd ); +static u16 usc_InReg( struct mgsl_struct *info, u16 Port ); +static void usc_OutReg( struct mgsl_struct *info, u16 Port, u16 Value ); +static void usc_RTCmd( struct mgsl_struct *info, u16 Cmd ); void usc_RCmd( struct mgsl_struct *info, u16 Cmd ); void usc_TCmd( struct mgsl_struct *info, u16 Cmd ); @@ -694,40 +693,39 @@ void usc_TCmd( struct mgsl_struct *info, u16 Cmd ); #define usc_SetTransmitSyncChars(a,s0,s1) usc_OutReg((a), TSR, (u16)(((u16)s0<<8)|(u16)s1)) -void usc_process_rxoverrun_sync( struct mgsl_struct *info ); -void usc_start_receiver( struct mgsl_struct *info ); -void usc_stop_receiver( struct mgsl_struct *info ); +static void usc_process_rxoverrun_sync( struct mgsl_struct *info ); +static void usc_start_receiver( struct mgsl_struct *info ); +static void usc_stop_receiver( struct mgsl_struct *info ); -void usc_start_transmitter( struct mgsl_struct *info ); -void usc_stop_transmitter( struct mgsl_struct *info ); -void usc_set_txidle( struct mgsl_struct *info ); -void usc_load_txfifo( struct mgsl_struct *info ); +static void usc_start_transmitter( struct mgsl_struct *info ); +static void usc_stop_transmitter( struct mgsl_struct *info ); +static void usc_set_txidle( struct mgsl_struct *info ); +static void usc_load_txfifo( struct mgsl_struct *info ); -void usc_enable_aux_clock( struct mgsl_struct *info, u32 DataRate ); -void usc_enable_loopback( struct mgsl_struct *info, int enable ); +static void usc_enable_aux_clock( struct mgsl_struct *info, u32 DataRate ); +static void usc_enable_loopback( struct mgsl_struct *info, int enable ); -void usc_get_serial_signals( struct mgsl_struct *info ); -void usc_set_serial_signals( struct mgsl_struct *info ); +static void usc_get_serial_signals( struct mgsl_struct *info ); +static void usc_set_serial_signals( struct mgsl_struct *info ); -void usc_reset( struct mgsl_struct *info ); +static void usc_reset( struct mgsl_struct *info ); -void usc_set_sync_mode( struct mgsl_struct *info ); -void usc_set_sdlc_mode( struct mgsl_struct *info ); -void usc_set_async_mode( struct mgsl_struct *info ); -void usc_enable_async_clock( struct mgsl_struct *info, u32 DataRate ); +static void usc_set_sync_mode( struct mgsl_struct *info ); +static void usc_set_sdlc_mode( struct mgsl_struct *info ); +static void usc_set_async_mode( struct mgsl_struct *info ); +static void usc_enable_async_clock( struct mgsl_struct *info, u32 DataRate ); -void usc_loopback_frame( struct mgsl_struct *info ); +static void usc_loopback_frame( struct mgsl_struct *info ); -void mgsl_tx_timeout(unsigned long context); +static void mgsl_tx_timeout(unsigned long context); -void usc_loopmode_cancel_transmit( struct mgsl_struct * info ); -void usc_loopmode_insert_request( struct mgsl_struct * info ); -int usc_loopmode_active( struct mgsl_struct * info); -void usc_loopmode_send_done( struct mgsl_struct * info ); -int usc_loopmode_send_active( struct mgsl_struct * info ); +static void usc_loopmode_cancel_transmit( struct mgsl_struct * info ); +static void usc_loopmode_insert_request( struct mgsl_struct * info ); +static int usc_loopmode_active( struct mgsl_struct * info); +static void usc_loopmode_send_done( struct mgsl_struct * info ); -int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg); +static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg); #ifdef CONFIG_HDLC #define dev_to_port(D) (dev_to_hdlc(D)->priv) @@ -753,77 +751,77 @@ static void hdlcdev_exit(struct mgsl_struct *info); ((Nrdd) << 11) + \ ((Nrad) << 6) ) -void mgsl_trace_block(struct mgsl_struct *info,const char* data, int count, int xmit); +static void mgsl_trace_block(struct mgsl_struct *info,const char* data, int count, int xmit); /* * Adapter diagnostic routines */ -BOOLEAN mgsl_register_test( struct mgsl_struct *info ); -BOOLEAN mgsl_irq_test( struct mgsl_struct *info ); -BOOLEAN mgsl_dma_test( struct mgsl_struct *info ); -BOOLEAN mgsl_memory_test( struct mgsl_struct *info ); -int mgsl_adapter_test( struct mgsl_struct *info ); +static BOOLEAN mgsl_register_test( struct mgsl_struct *info ); +static BOOLEAN mgsl_irq_test( struct mgsl_struct *info ); +static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ); +static BOOLEAN mgsl_memory_test( struct mgsl_struct *info ); +static int mgsl_adapter_test( struct mgsl_struct *info ); /* * device and resource management routines */ -int mgsl_claim_resources(struct mgsl_struct *info); -void mgsl_release_resources(struct mgsl_struct *info); -void mgsl_add_device(struct mgsl_struct *info); -struct mgsl_struct* mgsl_allocate_device(void); +static int mgsl_claim_resources(struct mgsl_struct *info); +static void mgsl_release_resources(struct mgsl_struct *info); +static void mgsl_add_device(struct mgsl_struct *info); +static struct mgsl_struct* mgsl_allocate_device(void); /* * DMA buffer manupulation functions. */ -void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ); -int mgsl_get_rx_frame( struct mgsl_struct *info ); -int mgsl_get_raw_rx_frame( struct mgsl_struct *info ); -void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ); -void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ); -int num_free_tx_dma_buffers(struct mgsl_struct *info); -void mgsl_load_tx_dma_buffer( struct mgsl_struct *info, const char *Buffer, unsigned int BufferSize); -void mgsl_load_pci_memory(char* TargetPtr, const char* SourcePtr, unsigned short count); +static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ); +static int mgsl_get_rx_frame( struct mgsl_struct *info ); +static int mgsl_get_raw_rx_frame( struct mgsl_struct *info ); +static void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ); +static void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ); +static int num_free_tx_dma_buffers(struct mgsl_struct *info); +static void mgsl_load_tx_dma_buffer( struct mgsl_struct *info, const char *Buffer, unsigned int BufferSize); +static void mgsl_load_pci_memory(char* TargetPtr, const char* SourcePtr, unsigned short count); /* * DMA and Shared Memory buffer allocation and formatting */ -int mgsl_allocate_dma_buffers(struct mgsl_struct *info); -void mgsl_free_dma_buffers(struct mgsl_struct *info); -int mgsl_alloc_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList,int Buffercount); -void mgsl_free_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList,int Buffercount); -int mgsl_alloc_buffer_list_memory(struct mgsl_struct *info); -void mgsl_free_buffer_list_memory(struct mgsl_struct *info); -int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info); -void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info); -int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info); -void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info); -int load_next_tx_holding_buffer(struct mgsl_struct *info); -int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize); +static int mgsl_allocate_dma_buffers(struct mgsl_struct *info); +static void mgsl_free_dma_buffers(struct mgsl_struct *info); +static int mgsl_alloc_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList,int Buffercount); +static void mgsl_free_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList,int Buffercount); +static int mgsl_alloc_buffer_list_memory(struct mgsl_struct *info); +static void mgsl_free_buffer_list_memory(struct mgsl_struct *info); +static int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info); +static void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info); +static int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info); +static void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info); +static int load_next_tx_holding_buffer(struct mgsl_struct *info); +static int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize); /* * Bottom half interrupt handlers */ -void mgsl_bh_handler(void* Context); -void mgsl_bh_receive(struct mgsl_struct *info); -void mgsl_bh_transmit(struct mgsl_struct *info); -void mgsl_bh_status(struct mgsl_struct *info); +static void mgsl_bh_handler(void* Context); +static void mgsl_bh_receive(struct mgsl_struct *info); +static void mgsl_bh_transmit(struct mgsl_struct *info); +static void mgsl_bh_status(struct mgsl_struct *info); /* * Interrupt handler routines and dispatch table. */ -void mgsl_isr_null( struct mgsl_struct *info ); -void mgsl_isr_transmit_data( struct mgsl_struct *info ); -void mgsl_isr_receive_data( struct mgsl_struct *info ); -void mgsl_isr_receive_status( struct mgsl_struct *info ); -void mgsl_isr_transmit_status( struct mgsl_struct *info ); -void mgsl_isr_io_pin( struct mgsl_struct *info ); -void mgsl_isr_misc( struct mgsl_struct *info ); -void mgsl_isr_receive_dma( struct mgsl_struct *info ); -void mgsl_isr_transmit_dma( struct mgsl_struct *info ); +static void mgsl_isr_null( struct mgsl_struct *info ); +static void mgsl_isr_transmit_data( struct mgsl_struct *info ); +static void mgsl_isr_receive_data( struct mgsl_struct *info ); +static void mgsl_isr_receive_status( struct mgsl_struct *info ); +static void mgsl_isr_transmit_status( struct mgsl_struct *info ); +static void mgsl_isr_io_pin( struct mgsl_struct *info ); +static void mgsl_isr_misc( struct mgsl_struct *info ); +static void mgsl_isr_receive_dma( struct mgsl_struct *info ); +static void mgsl_isr_transmit_dma( struct mgsl_struct *info ); typedef void (*isr_dispatch_func)(struct mgsl_struct *); -isr_dispatch_func UscIsrTable[7] = +static isr_dispatch_func UscIsrTable[7] = { mgsl_isr_null, mgsl_isr_misc, @@ -858,7 +856,7 @@ static int pci_registered; /* * Global linked list of SyncLink devices */ -struct mgsl_struct *mgsl_device_list; +static struct mgsl_struct *mgsl_device_list; static int mgsl_device_count; /* @@ -935,7 +933,7 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout); * (gdb) to get the .text address for the add-symbol-file command. * This allows remote debugging of dynamically loadable modules. */ -void* mgsl_get_text_ptr(void) +static void* mgsl_get_text_ptr(void) { return mgsl_get_text_ptr; } @@ -1052,7 +1050,7 @@ static void mgsl_start(struct tty_struct *tty) /* mgsl_bh_action() Return next bottom half action to perform. * Return Value: BH action code or 0 if nothing to do. */ -int mgsl_bh_action(struct mgsl_struct *info) +static int mgsl_bh_action(struct mgsl_struct *info) { unsigned long flags; int rc = 0; @@ -1084,7 +1082,7 @@ int mgsl_bh_action(struct mgsl_struct *info) /* * Perform bottom half processing of work items queued by ISR. */ -void mgsl_bh_handler(void* Context) +static void mgsl_bh_handler(void* Context) { struct mgsl_struct *info = (struct mgsl_struct*)Context; int action; @@ -1128,7 +1126,7 @@ void mgsl_bh_handler(void* Context) __FILE__,__LINE__,info->device_name); } -void mgsl_bh_receive(struct mgsl_struct *info) +static void mgsl_bh_receive(struct mgsl_struct *info) { int (*get_rx_frame)(struct mgsl_struct *info) = (info->params.mode == MGSL_MODE_HDLC ? mgsl_get_rx_frame : mgsl_get_raw_rx_frame); @@ -1149,7 +1147,7 @@ void mgsl_bh_receive(struct mgsl_struct *info) } while(get_rx_frame(info)); } -void mgsl_bh_transmit(struct mgsl_struct *info) +static void mgsl_bh_transmit(struct mgsl_struct *info) { struct tty_struct *tty = info->tty; unsigned long flags; @@ -1172,7 +1170,7 @@ void mgsl_bh_transmit(struct mgsl_struct *info) spin_unlock_irqrestore(&info->irq_spinlock,flags); } -void mgsl_bh_status(struct mgsl_struct *info) +static void mgsl_bh_status(struct mgsl_struct *info) { if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):mgsl_bh_status() entry on %s\n", @@ -1193,7 +1191,7 @@ void mgsl_bh_status(struct mgsl_struct *info) * Arguments: info pointer to device instance data * Return Value: None */ -void mgsl_isr_receive_status( struct mgsl_struct *info ) +static void mgsl_isr_receive_status( struct mgsl_struct *info ) { u16 status = usc_InReg( info, RCSR ); @@ -1245,7 +1243,7 @@ void mgsl_isr_receive_status( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: None */ -void mgsl_isr_transmit_status( struct mgsl_struct *info ) +static void mgsl_isr_transmit_status( struct mgsl_struct *info ) { u16 status = usc_InReg( info, TCSR ); @@ -1312,7 +1310,7 @@ void mgsl_isr_transmit_status( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: None */ -void mgsl_isr_io_pin( struct mgsl_struct *info ) +static void mgsl_isr_io_pin( struct mgsl_struct *info ) { struct mgsl_icount *icount; u16 status = usc_InReg( info, MISR ); @@ -1430,7 +1428,7 @@ void mgsl_isr_io_pin( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: None */ -void mgsl_isr_transmit_data( struct mgsl_struct *info ) +static void mgsl_isr_transmit_data( struct mgsl_struct *info ) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):mgsl_isr_transmit_data xmit_cnt=%d\n", @@ -1462,7 +1460,7 @@ void mgsl_isr_transmit_data( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: None */ -void mgsl_isr_receive_data( struct mgsl_struct *info ) +static void mgsl_isr_receive_data( struct mgsl_struct *info ) { int Fifocount; u16 status; @@ -1574,7 +1572,7 @@ void mgsl_isr_receive_data( struct mgsl_struct *info ) * Arguments: info pointer to device extension (instance data) * Return Value: None */ -void mgsl_isr_misc( struct mgsl_struct *info ) +static void mgsl_isr_misc( struct mgsl_struct *info ) { u16 status = usc_InReg( info, MISR ); @@ -1610,7 +1608,7 @@ void mgsl_isr_misc( struct mgsl_struct *info ) * Arguments: info pointer to device extension (instance data) * Return Value: None */ -void mgsl_isr_null( struct mgsl_struct *info ) +static void mgsl_isr_null( struct mgsl_struct *info ) { } /* end of mgsl_isr_null() */ @@ -1634,7 +1632,7 @@ void mgsl_isr_null( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: None */ -void mgsl_isr_receive_dma( struct mgsl_struct *info ) +static void mgsl_isr_receive_dma( struct mgsl_struct *info ) { u16 status; @@ -1678,7 +1676,7 @@ void mgsl_isr_receive_dma( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: None */ -void mgsl_isr_transmit_dma( struct mgsl_struct *info ) +static void mgsl_isr_transmit_dma( struct mgsl_struct *info ) { u16 status; @@ -2990,7 +2988,7 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file, return mgsl_ioctl_common(info, cmd, arg); } -int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg) +static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg) { int error; struct mgsl_icount cnow; /* kernel counter temps */ @@ -3649,7 +3647,7 @@ static inline int line_info(char *buf, struct mgsl_struct *info) * * Return Value: */ -int mgsl_read_proc(char *page, char **start, off_t off, int count, +static int mgsl_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0, l; @@ -3688,7 +3686,7 @@ done: * Arguments: info pointer to device instance data * Return Value: 0 if success, otherwise error */ -int mgsl_allocate_dma_buffers(struct mgsl_struct *info) +static int mgsl_allocate_dma_buffers(struct mgsl_struct *info) { unsigned short BuffersPerFrame; @@ -3795,7 +3793,7 @@ int mgsl_allocate_dma_buffers(struct mgsl_struct *info) * Arguments: info pointer to device instance data * Return Value: 0 if success, otherwise error */ -int mgsl_alloc_buffer_list_memory( struct mgsl_struct *info ) +static int mgsl_alloc_buffer_list_memory( struct mgsl_struct *info ) { unsigned int i; @@ -3880,7 +3878,7 @@ int mgsl_alloc_buffer_list_memory( struct mgsl_struct *info ) * the buffer list contains the information necessary to free * the individual buffers! */ -void mgsl_free_buffer_list_memory( struct mgsl_struct *info ) +static void mgsl_free_buffer_list_memory( struct mgsl_struct *info ) { if ( info->buffer_list && info->bus_type != MGSL_BUS_TYPE_PCI ) kfree(info->buffer_list); @@ -3907,7 +3905,7 @@ void mgsl_free_buffer_list_memory( struct mgsl_struct *info ) * * Return Value: 0 if success, otherwise -ENOMEM */ -int mgsl_alloc_frame_memory(struct mgsl_struct *info,DMABUFFERENTRY *BufferList,int Buffercount) +static int mgsl_alloc_frame_memory(struct mgsl_struct *info,DMABUFFERENTRY *BufferList,int Buffercount) { int i; unsigned long phys_addr; @@ -3949,7 +3947,7 @@ int mgsl_alloc_frame_memory(struct mgsl_struct *info,DMABUFFERENTRY *BufferList, * * Return Value: None */ -void mgsl_free_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList, int Buffercount) +static void mgsl_free_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList, int Buffercount) { int i; @@ -3972,7 +3970,7 @@ void mgsl_free_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList * Arguments: info pointer to device instance data * Return Value: None */ -void mgsl_free_dma_buffers( struct mgsl_struct *info ) +static void mgsl_free_dma_buffers( struct mgsl_struct *info ) { mgsl_free_frame_memory( info, info->rx_buffer_list, info->rx_buffer_count ); mgsl_free_frame_memory( info, info->tx_buffer_list, info->tx_buffer_count ); @@ -3993,7 +3991,7 @@ void mgsl_free_dma_buffers( struct mgsl_struct *info ) * * Return Value: 0 if success, otherwise -ENOMEM */ -int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info) +static int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info) { info->intermediate_rxbuffer = kmalloc(info->max_frame_size, GFP_KERNEL | GFP_DMA); if ( info->intermediate_rxbuffer == NULL ) @@ -4013,7 +4011,7 @@ int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info) * * Return Value: None */ -void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info) +static void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info) { if ( info->intermediate_rxbuffer ) kfree(info->intermediate_rxbuffer); @@ -4035,7 +4033,7 @@ void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info) * * Return Value: 0 if success, otherwise -ENOMEM */ -int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info) +static int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info) { int i; @@ -4066,7 +4064,7 @@ int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info) * * Return Value: None */ -void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info) +static void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info) { int i; @@ -4098,7 +4096,7 @@ void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info) * into adapter's tx dma buffer, * 0 otherwise */ -int load_next_tx_holding_buffer(struct mgsl_struct *info) +static int load_next_tx_holding_buffer(struct mgsl_struct *info) { int ret = 0; @@ -4144,7 +4142,7 @@ int load_next_tx_holding_buffer(struct mgsl_struct *info) * * Return Value: 1 if able to store, 0 otherwise */ -int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize) +static int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize) { struct tx_holding_buffer *ptx; @@ -4163,7 +4161,7 @@ int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned return 1; } -int mgsl_claim_resources(struct mgsl_struct *info) +static int mgsl_claim_resources(struct mgsl_struct *info) { if (request_region(info->io_base,info->io_addr_size,"synclink") == NULL) { printk( "%s(%d):I/O address conflict on device %s Addr=%08X\n", @@ -4243,7 +4241,7 @@ errout: } /* end of mgsl_claim_resources() */ -void mgsl_release_resources(struct mgsl_struct *info) +static void mgsl_release_resources(struct mgsl_struct *info) { if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):mgsl_release_resources(%s) entry\n", @@ -4297,7 +4295,7 @@ void mgsl_release_resources(struct mgsl_struct *info) * Arguments: info pointer to device instance data * Return Value: None */ -void mgsl_add_device( struct mgsl_struct *info ) +static void mgsl_add_device( struct mgsl_struct *info ) { info->next_device = NULL; info->line = mgsl_device_count; @@ -4363,7 +4361,7 @@ void mgsl_add_device( struct mgsl_struct *info ) * Arguments: none * Return Value: pointer to mgsl_struct if success, otherwise NULL */ -struct mgsl_struct* mgsl_allocate_device(void) +static struct mgsl_struct* mgsl_allocate_device(void) { struct mgsl_struct *info; @@ -4582,7 +4580,7 @@ module_exit(synclink_exit); * * None */ -void usc_RTCmd( struct mgsl_struct *info, u16 Cmd ) +static void usc_RTCmd( struct mgsl_struct *info, u16 Cmd ) { /* output command to CCAR in bits <15..11> */ /* preserve bits <10..7>, bits <6..0> must be zero */ @@ -4609,7 +4607,7 @@ void usc_RTCmd( struct mgsl_struct *info, u16 Cmd ) * * None */ -void usc_DmaCmd( struct mgsl_struct *info, u16 Cmd ) +static void usc_DmaCmd( struct mgsl_struct *info, u16 Cmd ) { /* write command mask to DCAR */ outw( Cmd + info->mbre_bit, info->io_base ); @@ -4636,7 +4634,7 @@ void usc_DmaCmd( struct mgsl_struct *info, u16 Cmd ) * None * */ -void usc_OutDmaReg( struct mgsl_struct *info, u16 RegAddr, u16 RegValue ) +static void usc_OutDmaReg( struct mgsl_struct *info, u16 RegAddr, u16 RegValue ) { /* Note: The DCAR is located at the adapter base address */ /* Note: must preserve state of BIT8 in DCAR */ @@ -4665,7 +4663,7 @@ void usc_OutDmaReg( struct mgsl_struct *info, u16 RegAddr, u16 RegValue ) * The 16-bit value read from register * */ -u16 usc_InDmaReg( struct mgsl_struct *info, u16 RegAddr ) +static u16 usc_InDmaReg( struct mgsl_struct *info, u16 RegAddr ) { /* Note: The DCAR is located at the adapter base address */ /* Note: must preserve state of BIT8 in DCAR */ @@ -4692,7 +4690,7 @@ u16 usc_InDmaReg( struct mgsl_struct *info, u16 RegAddr ) * None * */ -void usc_OutReg( struct mgsl_struct *info, u16 RegAddr, u16 RegValue ) +static void usc_OutReg( struct mgsl_struct *info, u16 RegAddr, u16 RegValue ) { outw( RegAddr + info->loopback_bits, info->io_base + CCAR ); outw( RegValue, info->io_base + CCAR ); @@ -4717,7 +4715,7 @@ void usc_OutReg( struct mgsl_struct *info, u16 RegAddr, u16 RegValue ) * * 16-bit value read from register */ -u16 usc_InReg( struct mgsl_struct *info, u16 RegAddr ) +static u16 usc_InReg( struct mgsl_struct *info, u16 RegAddr ) { outw( RegAddr + info->loopback_bits, info->io_base + CCAR ); return inw( info->io_base + CCAR ); @@ -4731,7 +4729,7 @@ u16 usc_InReg( struct mgsl_struct *info, u16 RegAddr ) * Arguments: info pointer to device instance data * Return Value: NONE */ -void usc_set_sdlc_mode( struct mgsl_struct *info ) +static void usc_set_sdlc_mode( struct mgsl_struct *info ) { u16 RegValue; int PreSL1660; @@ -5311,7 +5309,7 @@ void usc_set_sdlc_mode( struct mgsl_struct *info ) * enable 1 = enable loopback, 0 = disable * Return Value: None */ -void usc_enable_loopback(struct mgsl_struct *info, int enable) +static void usc_enable_loopback(struct mgsl_struct *info, int enable) { if (enable) { /* blank external TXD output */ @@ -5375,7 +5373,7 @@ void usc_enable_loopback(struct mgsl_struct *info, int enable) * * Return Value: None */ -void usc_enable_aux_clock( struct mgsl_struct *info, u32 data_rate ) +static void usc_enable_aux_clock( struct mgsl_struct *info, u32 data_rate ) { u32 XtalSpeed; u16 Tc; @@ -5432,7 +5430,7 @@ void usc_enable_aux_clock( struct mgsl_struct *info, u32 data_rate ) * * Return Value: None */ -void usc_process_rxoverrun_sync( struct mgsl_struct *info ) +static void usc_process_rxoverrun_sync( struct mgsl_struct *info ) { int start_index; int end_index; @@ -5571,7 +5569,7 @@ void usc_process_rxoverrun_sync( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: None */ -void usc_stop_receiver( struct mgsl_struct *info ) +static void usc_stop_receiver( struct mgsl_struct *info ) { if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):usc_stop_receiver(%s)\n", @@ -5604,7 +5602,7 @@ void usc_stop_receiver( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: None */ -void usc_start_receiver( struct mgsl_struct *info ) +static void usc_start_receiver( struct mgsl_struct *info ) { u32 phys_addr; @@ -5668,7 +5666,7 @@ void usc_start_receiver( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: None */ -void usc_start_transmitter( struct mgsl_struct *info ) +static void usc_start_transmitter( struct mgsl_struct *info ) { u32 phys_addr; unsigned int FrameSize; @@ -5774,7 +5772,7 @@ void usc_start_transmitter( struct mgsl_struct *info ) * Arguments: info pointer to device isntance data * Return Value: None */ -void usc_stop_transmitter( struct mgsl_struct *info ) +static void usc_stop_transmitter( struct mgsl_struct *info ) { if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):usc_stop_transmitter(%s)\n", @@ -5803,7 +5801,7 @@ void usc_stop_transmitter( struct mgsl_struct *info ) * Arguments: info pointer to device extension (instance data) * Return Value: None */ -void usc_load_txfifo( struct mgsl_struct *info ) +static void usc_load_txfifo( struct mgsl_struct *info ) { int Fifocount; u8 TwoBytes[2]; @@ -5860,7 +5858,7 @@ void usc_load_txfifo( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: None */ -void usc_reset( struct mgsl_struct *info ) +static void usc_reset( struct mgsl_struct *info ) { if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { int i; @@ -5974,7 +5972,7 @@ void usc_reset( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: None */ -void usc_set_async_mode( struct mgsl_struct *info ) +static void usc_set_async_mode( struct mgsl_struct *info ) { u16 RegValue; @@ -6167,7 +6165,7 @@ void usc_set_async_mode( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: None */ -void usc_loopback_frame( struct mgsl_struct *info ) +static void usc_loopback_frame( struct mgsl_struct *info ) { int i; unsigned long oldmode = info->params.mode; @@ -6235,7 +6233,7 @@ void usc_loopback_frame( struct mgsl_struct *info ) * Arguments: info pointer to adapter info structure * Return Value: None */ -void usc_set_sync_mode( struct mgsl_struct *info ) +static void usc_set_sync_mode( struct mgsl_struct *info ) { usc_loopback_frame( info ); usc_set_sdlc_mode( info ); @@ -6258,7 +6256,7 @@ void usc_set_sync_mode( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: None */ -void usc_set_txidle( struct mgsl_struct *info ) +static void usc_set_txidle( struct mgsl_struct *info ) { u16 usc_idle_mode = IDLEMODE_FLAGS; @@ -6321,7 +6319,7 @@ void usc_set_txidle( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: None */ -void usc_get_serial_signals( struct mgsl_struct *info ) +static void usc_get_serial_signals( struct mgsl_struct *info ) { u16 status; @@ -6357,7 +6355,7 @@ void usc_get_serial_signals( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: None */ -void usc_set_serial_signals( struct mgsl_struct *info ) +static void usc_set_serial_signals( struct mgsl_struct *info ) { u16 Control; unsigned char V24Out = info->serial_signals; @@ -6389,7 +6387,7 @@ void usc_set_serial_signals( struct mgsl_struct *info ) * 0 disables the AUX clock. * Return Value: None */ -void usc_enable_async_clock( struct mgsl_struct *info, u32 data_rate ) +static void usc_enable_async_clock( struct mgsl_struct *info, u32 data_rate ) { if ( data_rate ) { /* @@ -6499,7 +6497,7 @@ void usc_enable_async_clock( struct mgsl_struct *info, u32 data_rate ) * Arguments: info pointer to device instance data * Return Value: None */ -void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ) +static void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ) { unsigned int i; @@ -6525,7 +6523,7 @@ void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: number of free tx dma buffers */ -int num_free_tx_dma_buffers(struct mgsl_struct *info) +static int num_free_tx_dma_buffers(struct mgsl_struct *info) { return info->tx_buffer_count - info->tx_dma_buffers_used; } @@ -6540,7 +6538,7 @@ int num_free_tx_dma_buffers(struct mgsl_struct *info) * Arguments: info pointer to device instance data * Return Value: None */ -void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ) +static void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ) { unsigned int i; @@ -6568,7 +6566,7 @@ void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ) * * Return Value: None */ -void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ) +static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ) { int Done = 0; DMABUFFERENTRY *pBufEntry; @@ -6611,7 +6609,7 @@ void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartInd * Arguments: info pointer to device extension * Return Value: 1 if frame returned, otherwise 0 */ -int mgsl_get_rx_frame(struct mgsl_struct *info) +static int mgsl_get_rx_frame(struct mgsl_struct *info) { unsigned int StartIndex, EndIndex; /* index of 1st and last buffers of Rx frame */ unsigned short status; @@ -6810,7 +6808,7 @@ Cleanup: * Arguments: info pointer to device extension * Return Value: 1 if frame returned, otherwise 0 */ -int mgsl_get_raw_rx_frame(struct mgsl_struct *info) +static int mgsl_get_raw_rx_frame(struct mgsl_struct *info) { unsigned int CurrentIndex, NextIndex; unsigned short status; @@ -6975,8 +6973,8 @@ int mgsl_get_raw_rx_frame(struct mgsl_struct *info) * * Return Value: None */ -void mgsl_load_tx_dma_buffer(struct mgsl_struct *info, const char *Buffer, - unsigned int BufferSize) +static void mgsl_load_tx_dma_buffer(struct mgsl_struct *info, + const char *Buffer, unsigned int BufferSize) { unsigned short Copycount; unsigned int i = 0; @@ -7052,7 +7050,7 @@ void mgsl_load_tx_dma_buffer(struct mgsl_struct *info, const char *Buffer, * Arguments: info pointer to device instance data * Return Value: TRUE if test passed, otherwise FALSE */ -BOOLEAN mgsl_register_test( struct mgsl_struct *info ) +static BOOLEAN mgsl_register_test( struct mgsl_struct *info ) { static unsigned short BitPatterns[] = { 0x0000, 0xffff, 0xaaaa, 0x5555, 0x1234, 0x6969, 0x9696, 0x0f0f }; @@ -7108,7 +7106,7 @@ BOOLEAN mgsl_register_test( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: TRUE if test passed, otherwise FALSE */ -BOOLEAN mgsl_irq_test( struct mgsl_struct *info ) +static BOOLEAN mgsl_irq_test( struct mgsl_struct *info ) { unsigned long EndTime; unsigned long flags; @@ -7163,7 +7161,7 @@ BOOLEAN mgsl_irq_test( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: TRUE if test passed, otherwise FALSE */ -BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) +static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) { unsigned short FifoLevel; unsigned long phys_addr; @@ -7455,7 +7453,7 @@ BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: 0 if success, otherwise -ENODEV */ -int mgsl_adapter_test( struct mgsl_struct *info ) +static int mgsl_adapter_test( struct mgsl_struct *info ) { if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):Testing device %s\n", @@ -7497,7 +7495,7 @@ int mgsl_adapter_test( struct mgsl_struct *info ) * Arguments: info pointer to device instance data * Return Value: TRUE if test passed, otherwise FALSE */ -BOOLEAN mgsl_memory_test( struct mgsl_struct *info ) +static BOOLEAN mgsl_memory_test( struct mgsl_struct *info ) { static unsigned long BitPatterns[] = { 0x0, 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999, 0xffffffff, 0x12345678 }; @@ -7578,7 +7576,7 @@ BOOLEAN mgsl_memory_test( struct mgsl_struct *info ) * * Return Value: None */ -void mgsl_load_pci_memory( char* TargetPtr, const char* SourcePtr, +static void mgsl_load_pci_memory( char* TargetPtr, const char* SourcePtr, unsigned short count ) { /* 16 32-bit writes @ 60ns each = 960ns max latency on local bus */ @@ -7600,7 +7598,7 @@ void mgsl_load_pci_memory( char* TargetPtr, const char* SourcePtr, } /* End Of mgsl_load_pci_memory() */ -void mgsl_trace_block(struct mgsl_struct *info,const char* data, int count, int xmit) +static void mgsl_trace_block(struct mgsl_struct *info,const char* data, int count, int xmit) { int i; int linecount; @@ -7640,7 +7638,7 @@ void mgsl_trace_block(struct mgsl_struct *info,const char* data, int count, int * Arguments: context pointer to device instance data * Return Value: None */ -void mgsl_tx_timeout(unsigned long context) +static void mgsl_tx_timeout(unsigned long context) { struct mgsl_struct *info = (struct mgsl_struct*)context; unsigned long flags; @@ -7694,7 +7692,7 @@ static int mgsl_loopmode_send_done( struct mgsl_struct * info ) /* release the line by echoing RxD to TxD * upon completion of a transmit frame */ -void usc_loopmode_send_done( struct mgsl_struct * info ) +static void usc_loopmode_send_done( struct mgsl_struct * info ) { info->loopmode_send_done_requested = FALSE; /* clear CMR:13 to 0 to start echoing RxData to TxData */ @@ -7704,7 +7702,7 @@ void usc_loopmode_send_done( struct mgsl_struct * info ) /* abort a transmit in progress while in HDLC LoopMode */ -void usc_loopmode_cancel_transmit( struct mgsl_struct * info ) +static void usc_loopmode_cancel_transmit( struct mgsl_struct * info ) { /* reset tx dma channel and purge TxFifo */ usc_RTCmd( info, RTCmd_PurgeTxFifo ); @@ -7716,7 +7714,7 @@ void usc_loopmode_cancel_transmit( struct mgsl_struct * info ) * is an Insert Into Loop action. Upon receipt of a GoAhead sequence (RxAbort) * we must clear CMR:13 to begin repeating TxData to RxData */ -void usc_loopmode_insert_request( struct mgsl_struct * info ) +static void usc_loopmode_insert_request( struct mgsl_struct * info ) { info->loopmode_insert_requested = TRUE; @@ -7733,18 +7731,11 @@ void usc_loopmode_insert_request( struct mgsl_struct * info ) /* return 1 if station is inserted into the loop, otherwise 0 */ -int usc_loopmode_active( struct mgsl_struct * info) +static int usc_loopmode_active( struct mgsl_struct * info) { return usc_InReg( info, CCSR ) & BIT7 ? 1 : 0 ; } -/* return 1 if USC is in loop send mode, otherwise 0 - */ -int usc_loopmode_send_active( struct mgsl_struct * info ) -{ - return usc_InReg( info, CCSR ) & BIT6 ? 1 : 0 ; -} - #ifdef CONFIG_HDLC /** diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index 7696ead16862..0c5ba9dc9063 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -488,7 +488,7 @@ static struct parport_driver tipar_driver = { .detach = tipar_detach, }; -int __init +static int __init tipar_init_module(void) { int err = 0; @@ -525,7 +525,7 @@ out: return err; } -void __exit +static void __exit tipar_cleanup_module(void) { unsigned int i; diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index baf65901ab41..58e21fe44262 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -407,7 +407,7 @@ static int tosh_get_machine_id(void) * laptop, otherwise zero and determines the Machine ID, BIOS version and * date, and SCI version. */ -int tosh_probe(void) +static int tosh_probe(void) { int i,major,minor,day,year,month,flag; unsigned char signature[7] = { 0x54,0x4f,0x53,0x48,0x49,0x42,0x41 }; diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index ffc82ee87b37..0edec4f95c30 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -327,7 +327,7 @@ void tty_ldisc_put(int disc) EXPORT_SYMBOL_GPL(tty_ldisc_put); -void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) +static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) { tty->ldisc = *ld; tty->ldisc.refcount = 0; @@ -583,7 +583,7 @@ restart: /* * This routine returns a tty driver structure, given a device number */ -struct tty_driver *get_tty_driver(dev_t device, int *index) +static struct tty_driver *get_tty_driver(dev_t device, int *index) { struct tty_driver *p; @@ -744,7 +744,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); * but doesn't hold any locks, so we need to make sure we have the appropriate * locks for what we're doing.. */ -void do_tty_hangup(void *data) +static void do_tty_hangup(void *data) { struct tty_struct *tty = (struct tty_struct *) data; struct file * cons_filp = NULL; @@ -2523,28 +2523,6 @@ out: tty_ldisc_deref(disc); } -/* - * Call the ldisc flush directly from a driver. This function may - * return an error and need retrying by the user. - */ - -int tty_push_data(struct tty_struct *tty, unsigned char *cp, unsigned char *fp, int count) -{ - int ret = 0; - struct tty_ldisc *disc; - - disc = tty_ldisc_ref(tty); - if(test_bit(TTY_DONT_FLIP, &tty->flags)) - ret = -EAGAIN; - else if(disc == NULL) - ret = -EIO; - else - disc->receive_buf(tty, cp, fp, count); - tty_ldisc_deref(disc); - return ret; - -} - /* * Routine which returns the baud rate of the tty * diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 7145057e0a48..58597993954f 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -372,7 +372,7 @@ static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars) /* * Send a high priority character to the tty. */ -void send_prio_char(struct tty_struct *tty, char ch) +static void send_prio_char(struct tty_struct *tty, char ch) { int was_stopped = tty->stopped; diff --git a/include/linux/lp.h b/include/linux/lp.h index 521bcd2fecb1..7059b6b9878a 100644 --- a/include/linux/lp.h +++ b/include/linux/lp.h @@ -186,12 +186,6 @@ struct lp_struct { */ #define LP_DELAY 50 -/* - * function prototypes - */ - -extern int lp_init(void); - #endif #endif -- cgit v1.2.3 From b69ae6c23849111524f3f89cc0a45ee1742689d4 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 10 Jan 2005 17:24:52 -0800 Subject: [PATCH] efs: make a struct static (fwd) The patch below makes a needessly global struct in the efs code static. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/efs/super.c | 20 ++++++++++++++++++++ include/linux/efs_vh.h | 17 ----------------- 2 files changed, 20 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/fs/efs/super.c b/fs/efs/super.c index af4d01e2730a..d8d5ea9a9997 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -32,6 +32,26 @@ static struct file_system_type efs_fs_type = { .fs_flags = FS_REQUIRES_DEV, }; +static struct pt_types sgi_pt_types[] = { + {0x00, "SGI vh"}, + {0x01, "SGI trkrepl"}, + {0x02, "SGI secrepl"}, + {0x03, "SGI raw"}, + {0x04, "SGI bsd"}, + {SGI_SYSV, "SGI sysv"}, + {0x06, "SGI vol"}, + {SGI_EFS, "SGI efs"}, + {0x08, "SGI lv"}, + {0x09, "SGI rlv"}, + {0x0A, "SGI xfs"}, + {0x0B, "SGI xfslog"}, + {0x0C, "SGI xlv"}, + {0x82, "Linux swap"}, + {0x83, "Linux native"}, + {0, NULL} +}; + + static kmem_cache_t * efs_inode_cachep; static struct inode *efs_alloc_inode(struct super_block *sb) diff --git a/include/linux/efs_vh.h b/include/linux/efs_vh.h index b3df61ef2eb2..8a11150c61fe 100644 --- a/include/linux/efs_vh.h +++ b/include/linux/efs_vh.h @@ -47,23 +47,6 @@ struct volume_header { struct pt_types { int pt_type; char *pt_name; -} sgi_pt_types[] = { - {0x00, "SGI vh"}, - {0x01, "SGI trkrepl"}, - {0x02, "SGI secrepl"}, - {0x03, "SGI raw"}, - {0x04, "SGI bsd"}, - {SGI_SYSV, "SGI sysv"}, - {0x06, "SGI vol"}, - {SGI_EFS, "SGI efs"}, - {0x08, "SGI lv"}, - {0x09, "SGI rlv"}, - {0x0A, "SGI xfs"}, - {0x0B, "SGI xfslog"}, - {0x0C, "SGI xlv"}, - {0x82, "Linux swap"}, - {0x83, "Linux native"}, - {0, NULL} }; #endif /* __EFS_VH_H__ */ -- cgit v1.2.3 From 823986199ffd2928bcff8b6ab3c0dede78d19253 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 10 Jan 2005 17:25:07 -0800 Subject: [PATCH] ext3 cleanups - make some needlessly global code static - super.c: remove the unused global function ext3_panic Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext3/balloc.c | 2 +- fs/ext3/dir.c | 2 +- fs/ext3/inode.c | 4 +- fs/ext3/resize.c | 4 +- fs/ext3/super.c | 45 +++------ fs/ext3/xattr.c | 242 +++++++++++++++++++++++------------------------ fs/ext3/xattr.h | 8 -- include/linux/ext3_fs.h | 10 -- include/linux/ext3_jbd.h | 2 - 9 files changed, 143 insertions(+), 176 deletions(-) (limited to 'include/linux') diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index 4631ae139bf7..3f1b811ef2ad 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -1451,7 +1451,7 @@ static inline int test_root(int a, int b) } } -int ext3_group_sparse(int group) +static int ext3_group_sparse(int group) { return (test_root(group, 3) || test_root(group, 5) || test_root(group, 7)); diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c index b2bb90817371..832867aef3dc 100644 --- a/fs/ext3/dir.c +++ b/fs/ext3/dir.c @@ -306,7 +306,7 @@ static void free_rb_tree_fname(struct rb_root *root) } -struct dir_private_info *create_dir_info(loff_t pos) +static struct dir_private_info *create_dir_info(loff_t pos) { struct dir_private_info *p; diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 1132ad886f5a..0a92408946a9 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -39,6 +39,8 @@ #include "xattr.h" #include "acl.h" +static int ext3_writepage_trans_blocks(struct inode *inode); + /* * Test whether an inode is a fast symlink. */ @@ -2807,7 +2809,7 @@ err_out: * block and work out the exact number of indirects which are touched. Pah. */ -int ext3_writepage_trans_blocks(struct inode *inode) +static int ext3_writepage_trans_blocks(struct inode *inode) { int bpp = ext3_journal_blocks_per_page(inode); int indirects = (EXT3_NDIR_BLOCKS % bpp) ? 5 : 3; diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index b2786fac330d..2c9f81278d5d 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c @@ -285,8 +285,8 @@ exit_journal: * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ... * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ... */ -unsigned ext3_list_backups(struct super_block *sb, unsigned *three, - unsigned *five, unsigned *seven) +static unsigned ext3_list_backups(struct super_block *sb, unsigned *three, + unsigned *five, unsigned *seven) { unsigned *min = three; int mult = 3; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 9b654f7f29d7..d962d89e9ce1 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -50,6 +50,13 @@ static void ext3_mark_recovery_complete(struct super_block * sb, static void ext3_clear_journal_err(struct super_block * sb, struct ext3_super_block * es); static int ext3_sync_fs(struct super_block *sb, int wait); +static const char *ext3_decode_error(struct super_block * sb, int errno, + char nbuf[16]); +static int ext3_remount (struct super_block * sb, int * flags, char * data); +static int ext3_statfs (struct super_block * sb, struct kstatfs * buf); +static void ext3_unlockfs(struct super_block *sb); +static void ext3_write_super (struct super_block * sb); +static void ext3_write_super_lockfs(struct super_block *sb); /* * Wrappers for journal_start/end. @@ -178,7 +185,8 @@ void ext3_error (struct super_block * sb, const char * function, ext3_handle_error(sb); } -const char *ext3_decode_error(struct super_block * sb, int errno, char nbuf[16]) +static const char *ext3_decode_error(struct super_block * sb, int errno, + char nbuf[16]) { char *errstr = NULL; @@ -261,29 +269,6 @@ void ext3_abort (struct super_block * sb, const char * function, journal_abort(EXT3_SB(sb)->s_journal, -EIO); } -/* Deal with the reporting of failure conditions while running, such as - * inconsistencies in operation or invalid system states. - * - * Use ext3_error() for cases of invalid filesystem states, as that will - * record an error on disk and force a filesystem check on the next boot. - */ -NORET_TYPE void ext3_panic (struct super_block * sb, const char * function, - const char * fmt, ...) -{ - va_list args; - - va_start(args, fmt); - printk(KERN_CRIT "EXT3-fs error (device %s): %s: ",sb->s_id, function); - vprintk(fmt, args); - printk("\n"); - va_end(args); - - /* this is to prevent panic from syncing this filesystem */ - /* AKPM: is this sufficient? */ - sb->s_flags |= MS_RDONLY; - panic ("EXT3-fs panic forced\n"); -} - void ext3_warning (struct super_block * sb, const char * function, const char * fmt, ...) { @@ -386,7 +371,7 @@ static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi) } } -void ext3_put_super (struct super_block * sb) +static void ext3_put_super (struct super_block * sb) { struct ext3_sb_info *sbi = EXT3_SB(sb); struct ext3_super_block *es = sbi->s_es; @@ -2018,7 +2003,7 @@ int ext3_force_commit(struct super_block *sb) * This implicitly triggers the writebehind on sync(). */ -void ext3_write_super (struct super_block * sb) +static void ext3_write_super (struct super_block * sb) { if (down_trylock(&sb->s_lock) == 0) BUG(); @@ -2041,7 +2026,7 @@ static int ext3_sync_fs(struct super_block *sb, int wait) * LVM calls this function before a (read-only) snapshot is created. This * gives us a chance to flush the journal completely and mark the fs clean. */ -void ext3_write_super_lockfs(struct super_block *sb) +static void ext3_write_super_lockfs(struct super_block *sb) { sb->s_dirt = 0; @@ -2062,7 +2047,7 @@ void ext3_write_super_lockfs(struct super_block *sb) * Called by LVM after the snapshot is done. We need to reset the RECOVER * flag here, even though the filesystem is not technically dirty yet. */ -void ext3_unlockfs(struct super_block *sb) +static void ext3_unlockfs(struct super_block *sb) { if (!(sb->s_flags & MS_RDONLY)) { lock_super(sb); @@ -2074,7 +2059,7 @@ void ext3_unlockfs(struct super_block *sb) } } -int ext3_remount (struct super_block * sb, int * flags, char * data) +static int ext3_remount (struct super_block * sb, int * flags, char * data) { struct ext3_super_block * es; struct ext3_sb_info *sbi = EXT3_SB(sb); @@ -2146,7 +2131,7 @@ int ext3_remount (struct super_block * sb, int * flags, char * data) return 0; } -int ext3_statfs (struct super_block * sb, struct kstatfs * buf) +static int ext3_statfs (struct super_block * sb, struct kstatfs * buf) { struct ext3_super_block *es = EXT3_SB(sb)->s_es; unsigned long overhead; diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index 935778cc834f..31ef0eef09a3 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -138,23 +138,12 @@ ext3_xattr_handler(int name_index) return handler; } -/* - * Inode operation listxattr() - * - * dentry->d_inode->i_sem: don't care - */ -ssize_t -ext3_listxattr(struct dentry *dentry, char *buffer, size_t size) -{ - return ext3_xattr_list(dentry->d_inode, buffer, size); -} - /* * ext3_xattr_block_get() * * routine looks for attribute in EA block and returns it's value and size */ -int +static int ext3_xattr_block_get(struct inode *inode, int name_index, const char *name, void *buffer, size_t buffer_size) { @@ -250,7 +239,7 @@ cleanup: * * routine looks for attribute in inode body and returns it's value and size */ -int +static int ext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name, void *buffer, size_t buffer_size) { @@ -352,7 +341,7 @@ ext3_xattr_get(struct inode *inode, int name_index, const char *name, * * generate list of attributes stored in EA block */ -int +static int ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size) { struct buffer_head *bh = NULL; @@ -428,7 +417,7 @@ cleanup: * * generate list of attributes stored in inode body */ -int +static int ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size) { struct ext3_xattr_entry *last; @@ -507,7 +496,7 @@ cleanup: * Returns a negative error number on failure, or the number of bytes * used / required on success. */ -int +static int ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) { int size = buffer_size; @@ -545,6 +534,17 @@ cleanup: return error + size; } +/* + * Inode operation listxattr() + * + * dentry->d_inode->i_sem: don't care + */ +ssize_t +ext3_listxattr(struct dentry *dentry, char *buffer, size_t size) +{ + return ext3_xattr_list(dentry->d_inode, buffer, size); +} + /* * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is * not set, set it. @@ -571,7 +571,7 @@ static void ext3_xattr_update_super_block(handle_t *handle, * search attribute and calculate free space in inode body * NOTE: free space includes space our attribute hold */ -int +static int ext3_xattr_ibody_find(struct inode *inode, int name_index, const char *name, int *free) { @@ -638,7 +638,7 @@ ext3_xattr_ibody_find(struct inode *inode, int name_index, * search attribute and calculate free space in EA block (if it allocated) * NOTE: free space includes space our attribute hold */ -int +static int ext3_xattr_block_find(struct inode *inode, int name_index, const char *name, int *free) { @@ -698,7 +698,7 @@ bad_block: ext3_error(inode->i_sb, "ext3_xattr_get", * * this routine add/remove/replace attribute in inode body */ -int +static int ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, int name_index, const char *name, const void *value, size_t value_len, int flags) @@ -845,113 +845,12 @@ done: return 0; } -/* - * ext3_xattr_set_handle() - * - * Create, replace or remove an extended attribute for this inode. Buffer - * is NULL to remove an existing extended attribute, and non-NULL to - * either replace an existing extended attribute, or create a new extended - * attribute. The flags XATTR_REPLACE and XATTR_CREATE - * specify that an extended attribute must exist and must not exist - * previous to the call, respectively. - * - * Returns 0, or a negative error number on failure. - */ -int -ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, - const char *name, const void *value, size_t value_len, - int flags) -{ - int free1 = -1, free2 = -1; - int err, where = 0, total; - int name_len; - - ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", - name_index, name, value, (long)value_len); - - if (IS_RDONLY(inode)) - return -EROFS; - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - return -EPERM; - if (value == NULL) - value_len = 0; - if (name == NULL) - return -EINVAL; - name_len = strlen(name); - if (name_len > 255 || value_len > inode->i_sb->s_blocksize) - return -ERANGE; - down_write(&EXT3_I(inode)->xattr_sem); - -#define EX_FOUND_IN_IBODY 1 -#define EX_FOUND_IN_BLOCK 2 - - /* try to find attribute in inode body */ - err = ext3_xattr_ibody_find(inode, name_index, name, &free1); - if (err == 0) { - /* found EA in inode */ - where = EX_FOUND_IN_IBODY; - } else if (err == -ENOENT) { - /* there is no such attribute in inode body */ - /* try to find attribute in dedicated block */ - err = ext3_xattr_block_find(inode, name_index, name, &free2); - if (err != 0 && err != -ENOENT) { - /* not found EA in block */ - goto finish; - } else if (err == 0) { - /* found EA in block */ - where = EX_FOUND_IN_BLOCK; - } - } else - goto finish; - - /* check flags: may replace? may create ? */ - if (where && (flags & XATTR_CREATE)) { - err = -EEXIST; - goto finish; - } else if (!where && (flags & XATTR_REPLACE)) { - err = -ENODATA; - goto finish; - } - - /* check if we have enough space to store attribute */ - total = EXT3_XATTR_LEN(strlen(name)) + value_len; - if (total > free1 && free2 > 0 && total > free2) { - /* have no enough space */ - err = -ENOSPC; - goto finish; - } - - /* there are two cases when we want to remove EA from original storage: - * a) EA is stored in the inode, but new value doesn't fit - * b) EA is stored in the block, but new value fit in inode - */ - if (where == EX_FOUND_IN_IBODY && total > free1) - ext3_xattr_ibody_set(handle, inode, name_index, name, - NULL, 0, flags); - else if (where == EX_FOUND_IN_BLOCK && total <= free1) - ext3_xattr_block_set(handle, inode, name_index, - name, NULL, 0, flags); - - /* try to store EA in inode body */ - err = ext3_xattr_ibody_set(handle, inode, name_index, name, - value, value_len, flags); - if (err) { - /* can't store EA in inode body: try to store in block */ - err = ext3_xattr_block_set(handle, inode, name_index, name, - value, value_len, flags); - } - -finish: - up_write(&EXT3_I(inode)->xattr_sem); - return err; -} - /* * ext3_xattr_block_set() * * this routine add/remove/replace attribute in EA block */ -int +static int ext3_xattr_block_set(handle_t *handle, struct inode *inode, int name_index, const char *name, const void *value, size_t value_len, int flags) @@ -1205,6 +1104,107 @@ cleanup: return error; } +/* + * ext3_xattr_set_handle() + * + * Create, replace or remove an extended attribute for this inode. Buffer + * is NULL to remove an existing extended attribute, and non-NULL to + * either replace an existing extended attribute, or create a new extended + * attribute. The flags XATTR_REPLACE and XATTR_CREATE + * specify that an extended attribute must exist and must not exist + * previous to the call, respectively. + * + * Returns 0, or a negative error number on failure. + */ +int +ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, + const char *name, const void *value, size_t value_len, + int flags) +{ + int free1 = -1, free2 = -1; + int err, where = 0, total; + int name_len; + + ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", + name_index, name, value, (long)value_len); + + if (IS_RDONLY(inode)) + return -EROFS; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + return -EPERM; + if (value == NULL) + value_len = 0; + if (name == NULL) + return -EINVAL; + name_len = strlen(name); + if (name_len > 255 || value_len > inode->i_sb->s_blocksize) + return -ERANGE; + down_write(&EXT3_I(inode)->xattr_sem); + +#define EX_FOUND_IN_IBODY 1 +#define EX_FOUND_IN_BLOCK 2 + + /* try to find attribute in inode body */ + err = ext3_xattr_ibody_find(inode, name_index, name, &free1); + if (err == 0) { + /* found EA in inode */ + where = EX_FOUND_IN_IBODY; + } else if (err == -ENOENT) { + /* there is no such attribute in inode body */ + /* try to find attribute in dedicated block */ + err = ext3_xattr_block_find(inode, name_index, name, &free2); + if (err != 0 && err != -ENOENT) { + /* not found EA in block */ + goto finish; + } else if (err == 0) { + /* found EA in block */ + where = EX_FOUND_IN_BLOCK; + } + } else + goto finish; + + /* check flags: may replace? may create ? */ + if (where && (flags & XATTR_CREATE)) { + err = -EEXIST; + goto finish; + } else if (!where && (flags & XATTR_REPLACE)) { + err = -ENODATA; + goto finish; + } + + /* check if we have enough space to store attribute */ + total = EXT3_XATTR_LEN(strlen(name)) + value_len; + if (total > free1 && free2 > 0 && total > free2) { + /* have no enough space */ + err = -ENOSPC; + goto finish; + } + + /* there are two cases when we want to remove EA from original storage: + * a) EA is stored in the inode, but new value doesn't fit + * b) EA is stored in the block, but new value fit in inode + */ + if (where == EX_FOUND_IN_IBODY && total > free1) + ext3_xattr_ibody_set(handle, inode, name_index, name, + NULL, 0, flags); + else if (where == EX_FOUND_IN_BLOCK && total <= free1) + ext3_xattr_block_set(handle, inode, name_index, + name, NULL, 0, flags); + + /* try to store EA in inode body */ + err = ext3_xattr_ibody_set(handle, inode, name_index, name, + value, value_len, flags); + if (err) { + /* can't store EA in inode body: try to store in block */ + err = ext3_xattr_block_set(handle, inode, name_index, name, + value, value_len, flags); + } + +finish: + up_write(&EXT3_I(inode)->xattr_sem); + return err; +} + /* * Second half of ext3_xattr_set_handle(): Update the file system. */ diff --git a/fs/ext3/xattr.h b/fs/ext3/xattr.h index b677cf7ac568..b2b25ad82451 100644 --- a/fs/ext3/xattr.h +++ b/fs/ext3/xattr.h @@ -65,10 +65,8 @@ extern struct xattr_handler ext3_xattr_security_handler; extern ssize_t ext3_listxattr(struct dentry *, char *, size_t); extern int ext3_xattr_get(struct inode *, int, const char *, void *, size_t); -extern int ext3_xattr_list(struct inode *, char *, size_t); extern int ext3_xattr_set(struct inode *, int, const char *, const void *, size_t, int); extern int ext3_xattr_set_handle(handle_t *, struct inode *, int, const char *,const void *,size_t,int); -extern int ext3_xattr_block_set(handle_t *, struct inode *, int, const char *,const void *,size_t,int); extern void ext3_xattr_delete_inode(handle_t *, struct inode *); extern void ext3_xattr_put_super(struct super_block *); @@ -87,12 +85,6 @@ ext3_xattr_get(struct inode *inode, int name_index, const char *name, return -EOPNOTSUPP; } -static inline int -ext3_xattr_list(struct inode *inode, void *buffer, size_t size) -{ - return -EOPNOTSUPP; -} - static inline int ext3_xattr_set(struct inode *inode, int name_index, const char *name, const void *value, size_t size, int flags) diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index a45400d0a2f4..2789be67fbe9 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -793,25 +793,15 @@ extern void ext3_error (struct super_block *, const char *, const char *, ...) extern void __ext3_std_error (struct super_block *, const char *, int); extern void ext3_abort (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); -extern NORET_TYPE void ext3_panic (struct super_block *, const char *, - const char *, ...) - __attribute__ ((NORET_AND format (printf, 3, 4))); extern void ext3_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); extern void ext3_update_dynamic_rev (struct super_block *sb); -extern void ext3_put_super (struct super_block *); -extern void ext3_write_super (struct super_block *); -extern void ext3_write_super_lockfs (struct super_block *); -extern void ext3_unlockfs (struct super_block *); -extern int ext3_remount (struct super_block *, int *, char *); -extern int ext3_statfs (struct super_block *, struct kstatfs *); #define ext3_std_error(sb, errno) \ do { \ if ((errno)) \ __ext3_std_error((sb), __FUNCTION__, (errno)); \ } while (0) -extern const char *ext3_decode_error(struct super_block *sb, int errno, char nbuf[16]); /* * Inodes and files operations diff --git a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h index 0380c1fbdab0..47445f93d4f7 100644 --- a/include/linux/ext3_jbd.h +++ b/include/linux/ext3_jbd.h @@ -46,8 +46,6 @@ EXT3_XATTR_TRANS_BLOCKS - 2 + \ 2*EXT3_QUOTA_TRANS_BLOCKS) -extern int ext3_writepage_trans_blocks(struct inode *inode); - /* Delete operations potentially hit one directory's namespace plus an * entire inode, plus arbitrary amounts of bitmap/indirection data. Be * generous. We can grow the delete transaction later if necessary. */ -- cgit v1.2.3 From 111b88bf399406586f780f53c4b5e6d142a30bc4 Mon Sep 17 00:00:00 2001 From: "Andries E. Brouwer" Date: Mon, 10 Jan 2005 17:25:53 -0800 Subject: [PATCH] remove NR_SUPER define Last month I removed the "or too many mounted filesystems" part from an error message in mount(8) - NR_SUPER has not been used in a very long time. Also NR_RESERVED_FILES is unused today. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fs.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 31391d59ddc2..aa7abb112dbc 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -68,8 +68,6 @@ extern int dir_notify_enable; #endif #define NR_FILE 8192 /* this can well be larger on a larger system */ -#define NR_RESERVED_FILES 10 /* reserved for root */ -#define NR_SUPER 256 #define MAY_EXEC 1 #define MAY_WRITE 2 -- cgit v1.2.3 From e926095b7dd6e715d931486f16a85250807dae64 Mon Sep 17 00:00:00 2001 From: Jan Harkes Date: Mon, 10 Jan 2005 17:26:36 -0800 Subject: [PATCH] coda: bounds checking This patch adds bounds checks for tainted scalars (reported by Brian Fulton and Ted Unangst, Coverity Inc.). Signed-off-by: Jan Harkes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/coda/upcall.c | 26 +++++++++++++++++++------- include/linux/coda.h | 4 ++-- 2 files changed, 21 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index 569e144c661a..5ac4985bfe05 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -555,6 +555,11 @@ int venus_pioctl(struct super_block *sb, struct CodaFid *fid, goto exit; } + if (data->vi.out_size > VC_MAXDATASIZE) { + error = -EINVAL; + goto exit; + } + inp->coda_ioctl.VFid = *fid; /* the cmd field was mutated by increasing its size field to @@ -583,19 +588,26 @@ int venus_pioctl(struct super_block *sb, struct CodaFid *fid, error, coda_f2s(fid)); goto exit; } + + if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) { + error = -EINVAL; + goto exit; + } /* Copy out the OUT buffer. */ if (outp->coda_ioctl.len > data->vi.out_size) { error = -EINVAL; - } else { - if (copy_to_user(data->vi.out, - (char *)outp + (long)outp->coda_ioctl.data, - data->vi.out_size)) { - error = -EFAULT; - goto exit; - } + goto exit; } + /* Copy out the OUT buffer. */ + if (copy_to_user(data->vi.out, + (char *)outp + (long)outp->coda_ioctl.data, + outp->coda_ioctl.len)) { + error = -EFAULT; + goto exit; + } + exit: CODA_FREE(inp, insize); return error; diff --git a/include/linux/coda.h b/include/linux/coda.h index 309cbbe35e67..bbc5afcd7db6 100644 --- a/include/linux/coda.h +++ b/include/linux/coda.h @@ -761,8 +761,8 @@ union coda_downcalls { struct ViceIoctl { void __user *in; /* Data to be transferred in */ void __user *out; /* Data to be transferred out */ - short in_size; /* Size of input buffer <= 2K */ - short out_size; /* Maximum size of output buffer, <= 2K */ + u_short in_size; /* Size of input buffer <= 2K */ + u_short out_size; /* Maximum size of output buffer, <= 2K */ }; struct PioctlData { -- cgit v1.2.3 From fa34aea6ccc56aea96b2a531436508f2790d17e7 Mon Sep 17 00:00:00 2001 From: Jan Harkes Date: Mon, 10 Jan 2005 17:27:05 -0800 Subject: [PATCH] coda: make global code static The patch below makes some needlessly global code static. Signed-off-by: Adrian Bunk Signed-off-by: Jan Harkes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/coda/cnode.c | 2 +- fs/coda/dir.c | 2 +- fs/coda/file.c | 2 +- fs/coda/inode.c | 2 +- fs/coda/sysctl.c | 56 ++++++++++++++++++++++++----------------------- include/linux/coda_proc.h | 21 ------------------ 6 files changed, 33 insertions(+), 52 deletions(-) (limited to 'include/linux') diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c index 6bf72ebb1c57..23aeef5aa814 100644 --- a/fs/coda/cnode.c +++ b/fs/coda/cnode.c @@ -11,7 +11,7 @@ #include #include -inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2) +static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2) { return memcmp(fid1, fid2, sizeof(*fid1)) == 0; } diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 7397d7c93bd4..5e84f907cb73 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -55,7 +55,7 @@ int coda_fsync(struct file *, struct dentry *dentry, int datasync); int coda_hasmknod; -struct dentry_operations coda_dentry_operations = +static struct dentry_operations coda_dentry_operations = { .d_revalidate = coda_dentry_revalidate, .d_delete = coda_dentry_delete, diff --git a/fs/coda/file.c b/fs/coda/file.c index 960bda823d58..e6bc022568f3 100644 --- a/fs/coda/file.c +++ b/fs/coda/file.c @@ -26,7 +26,7 @@ /* if CODA_STORE fails with EOPNOTSUPP, venus clearly doesn't support * CODA_STORE/CODA_RELEASE and we fall back on using the CODA_CLOSE upcall */ -int use_coda_close; +static int use_coda_close; static ssize_t coda_file_read(struct file *coda_file, char __user *buf, size_t count, loff_t *ppos) diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 6a891bfc01de..04a73fb4848f 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -89,7 +89,7 @@ static int coda_remount(struct super_block *sb, int *flags, char *data) } /* exported operations */ -struct super_operations coda_super_operations = +static struct super_operations coda_super_operations = { .alloc_inode = coda_alloc_inode, .destroy_inode = coda_destroy_inode, diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c index 5b71f47e27dd..f0b10757288f 100644 --- a/fs/coda/sysctl.c +++ b/fs/coda/sysctl.c @@ -41,35 +41,22 @@ static struct ctl_table_header *fs_table_header; #define CODA_CACHE_INV 9 /* cache invalidation statistics */ #define CODA_FAKE_STATFS 10 /* don't query venus for actual cache usage */ -static ctl_table coda_table[] = { - {CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &proc_dointvec}, - {CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &proc_dointvec}, - {CODA_VFS, "vfs_stats", NULL, 0, 0644, NULL, &do_reset_coda_vfs_stats}, - {CODA_CACHE_INV, "cache_inv_stats", NULL, 0, 0644, NULL, &do_reset_coda_cache_inv_stats}, - {CODA_FAKE_STATFS, "fake_statfs", &coda_fake_statfs, sizeof(int), 0600, NULL, &proc_dointvec}, - { 0 } -}; - -static ctl_table fs_table[] = { - {FS_CODA, "coda", NULL, 0, 0555, coda_table}, - {0} -}; - struct coda_vfs_stats coda_vfs_stat; -struct coda_cache_inv_stats coda_cache_inv_stat; +static struct coda_cache_inv_stats coda_cache_inv_stat; -void reset_coda_vfs_stats( void ) +static void reset_coda_vfs_stats( void ) { memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) ); } -void reset_coda_cache_inv_stats( void ) +static void reset_coda_cache_inv_stats( void ) { memset( &coda_cache_inv_stat, 0, sizeof( coda_cache_inv_stat ) ); } -int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp, - void __user * buffer, size_t * lenp, loff_t * ppos ) +static int do_reset_coda_vfs_stats( ctl_table * table, int write, + struct file * filp, void __user * buffer, + size_t * lenp, loff_t * ppos ) { if ( write ) { reset_coda_vfs_stats(); @@ -82,9 +69,10 @@ int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp, return 0; } -int do_reset_coda_cache_inv_stats( ctl_table * table, int write, - struct file * filp, void __user * buffer, - size_t * lenp, loff_t * ppos ) +static int do_reset_coda_cache_inv_stats( ctl_table * table, int write, + struct file * filp, + void __user * buffer, + size_t * lenp, loff_t * ppos ) { if ( write ) { reset_coda_cache_inv_stats(); @@ -97,8 +85,8 @@ int do_reset_coda_cache_inv_stats( ctl_table * table, int write, return 0; } -int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset, - int length) +static int coda_vfs_stats_get_info( char * buffer, char ** start, + off_t offset, int length) { int len=0; off_t begin; @@ -158,8 +146,8 @@ int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset, return len; } -int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset, - int length) +static int coda_cache_inv_stats_get_info( char * buffer, char ** start, + off_t offset, int length) { int len=0; off_t begin; @@ -196,6 +184,20 @@ int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset, return len; } +static ctl_table coda_table[] = { + {CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &proc_dointvec}, + {CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &proc_dointvec}, + {CODA_VFS, "vfs_stats", NULL, 0, 0644, NULL, &do_reset_coda_vfs_stats}, + {CODA_CACHE_INV, "cache_inv_stats", NULL, 0, 0644, NULL, &do_reset_coda_cache_inv_stats}, + {CODA_FAKE_STATFS, "fake_statfs", &coda_fake_statfs, sizeof(int), 0600, NULL, &proc_dointvec}, + { 0 } +}; + +static ctl_table fs_table[] = { + {FS_CODA, "coda", NULL, 0, 0555, coda_table}, + {0} +}; + #ifdef CONFIG_PROC_FS @@ -207,7 +209,7 @@ int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset, */ -struct proc_dir_entry* proc_fs_coda; +static struct proc_dir_entry* proc_fs_coda; #endif diff --git a/include/linux/coda_proc.h b/include/linux/coda_proc.h index c061a22ed86d..0dc1b0458e75 100644 --- a/include/linux/coda_proc.h +++ b/include/linux/coda_proc.h @@ -72,26 +72,5 @@ struct coda_cache_inv_stats /* these global variables hold the actual statistics data */ extern struct coda_vfs_stats coda_vfs_stat; -extern struct coda_cache_inv_stats coda_cache_inv_stat; - -/* reset statistics to 0 */ -void reset_coda_vfs_stats( void ); -void reset_coda_cache_inv_stats( void ); - -/* like coda_dointvec, these functions are to be registered in the ctl_table - * data structure for /proc/sys/... files - */ -int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp, - void __user * buffer, size_t * lenp, loff_t * ppos ); -int do_reset_coda_cache_inv_stats( ctl_table * table, int write, - struct file * filp, void __user * buffer, - size_t * lenp, loff_t * ppos ); - -/* these functions are called to form the content of /proc/fs/coda/... files */ -int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset, - int length); -int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset, - int length); - #endif /* _CODA_PROC_H */ -- cgit v1.2.3 From ffd4550426f416fa430ddf5e303c66d504ccf9e4 Mon Sep 17 00:00:00 2001 From: Jan Harkes Date: Mon, 10 Jan 2005 17:27:21 -0800 Subject: [PATCH] coda: remove unused coda_mknod Remove coda_mknod as the code was never used, coda_hasmknod was always 0. (reported by Adrian Bunk) Signed-off-by: Jan Harkes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/coda/dir.c | 58 +++++++--------------------------------------- fs/coda/upcall.c | 3 +-- include/linux/coda_psdev.h | 2 +- 3 files changed, 10 insertions(+), 53 deletions(-) (limited to 'include/linux') diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 5e84f907cb73..2391766e9c7c 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -29,7 +29,6 @@ /* dir inode-ops */ static int coda_create(struct inode *dir, struct dentry *new, int mode, struct nameidata *nd); -static int coda_mknod(struct inode *dir, struct dentry *new, int mode, dev_t rdev); static struct dentry *coda_lookup(struct inode *dir, struct dentry *target, struct nameidata *nd); static int coda_link(struct dentry *old_dentry, struct inode *dir_inode, struct dentry *entry); @@ -53,7 +52,12 @@ static int coda_venus_readdir(struct file *filp, filldir_t filldir, void *dirent, struct dentry *dir); int coda_fsync(struct file *, struct dentry *dentry, int datasync); -int coda_hasmknod; +/* same as fs/bad_inode.c */ +static int coda_return_EIO(void) +{ + return -EIO; +} +#define CODA_EIO_ERROR ((void *) (coda_return_EIO)) static struct dentry_operations coda_dentry_operations = { @@ -70,7 +74,7 @@ struct inode_operations coda_dir_inode_operations = .symlink = coda_symlink, .mkdir = coda_mkdir, .rmdir = coda_rmdir, - .mknod = coda_mknod, + .mknod = CODA_EIO_ERROR, .rename = coda_rename, .permission = coda_permission, .getattr = coda_getattr, @@ -208,7 +212,7 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode, struct na } error = venus_create(dir->i_sb, coda_i2f(dir), name, length, - 0, mode, 0, &newfid, &attrs); + 0, mode, &newfid, &attrs); if ( error ) { unlock_kernel(); @@ -230,52 +234,6 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode, struct na return 0; } -static int coda_mknod(struct inode *dir, struct dentry *de, int mode, dev_t rdev) -{ - int error=0; - const char *name=de->d_name.name; - int length=de->d_name.len; - struct inode *inode; - struct CodaFid newfid; - struct coda_vattr attrs; - - if ( coda_hasmknod == 0 ) - return -EIO; - - if (!old_valid_dev(rdev)) - return -EINVAL; - - lock_kernel(); - coda_vfs_stat.create++; - - if (coda_isroot(dir) && coda_iscontrol(name, length)) { - unlock_kernel(); - return -EPERM; - } - - error = venus_create(dir->i_sb, coda_i2f(dir), name, length, - 0, mode, rdev, &newfid, &attrs); - - if ( error ) { - unlock_kernel(); - d_drop(de); - return error; - } - - inode = coda_iget(dir->i_sb, &newfid, &attrs); - if ( IS_ERR(inode) ) { - unlock_kernel(); - d_drop(de); - return PTR_ERR(inode); - } - - /* invalidate the directory cnode's attributes */ - coda_dir_changed(dir, 0); - unlock_kernel(); - d_instantiate(de, inode); - return 0; -} - static int coda_mkdir(struct inode *dir, struct dentry *de, int mode) { struct inode *inode; diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index 5ac4985bfe05..107dbfae7d13 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -331,7 +331,7 @@ int venus_rename(struct super_block *sb, struct CodaFid *old_fid, } int venus_create(struct super_block *sb, struct CodaFid *dirfid, - const char *name, int length, int excl, int mode, dev_t rdev, + const char *name, int length, int excl, int mode, struct CodaFid *newfid, struct coda_vattr *attrs) { union inputArgs *inp; @@ -345,7 +345,6 @@ int venus_create(struct super_block *sb, struct CodaFid *dirfid, inp->coda_create.VFid = *dirfid; inp->coda_create.attr.va_mode = mode; - inp->coda_create.attr.va_rdev = huge_encode_dev(rdev); inp->coda_create.excl = excl; inp->coda_create.mode = mode; inp->coda_create.name = offset; diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h index 0c767ffd6a0d..d539262a8f89 100644 --- a/include/linux/coda_psdev.h +++ b/include/linux/coda_psdev.h @@ -49,7 +49,7 @@ int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid, const char *name, int length, struct CodaFid *newfid, struct coda_vattr *attrs); int venus_create(struct super_block *sb, struct CodaFid *dirfid, - const char *name, int length, int excl, int mode, dev_t rdev, + const char *name, int length, int excl, int mode, struct CodaFid *newfid, struct coda_vattr *attrs) ; int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid, const char *name, int length); -- cgit v1.2.3 From 0a71336b6a8858a525007c5b4e0d14ba57f9f315 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 11 Jan 2005 01:40:38 -0800 Subject: [PATCH] cputime: introduce cputime This patch introduces the concept of (virtual) cputime. Each architecture can define its method to measure cputime. The main idea is to define a cputime_t type and a set of operations on it (see asm-generic/cputime.h). Then use the type for utime, stime, cutime, cstime, it_virt_value, it_virt_incr, it_prof_value and it_prof_incr and use the cputime operations for each access to these variables. The default implementation is jiffies based and the effect of this patch for architectures which use the default implementation should be neglectible. There is a second type cputime64_t which is necessary for the kernel_stat cpu statistics. The default cputime_t is 32 bit and based on HZ, this will overflow after 49.7 days. This is not enough for kernel_stat (ihmo not enough for a processes too), so it is necessary to have a 64 bit type. The third thing that gets introduced by this patch is an additional field for the /proc/stat interface: cpu steal time. An architecture can account cpu steal time by calls to the account_stealtime function. The cpu which backs a virtual processor doesn't spent all of its time for the virtual cpu. To get meaningful cpu usage numbers this involuntary wait time needs to be accounted and exported to user space. From: Hugh Dickins The p->signal check in account_system_time is insufficient. If the timer interrupt hits near the end of exit_notify, after EXIT_ZOMBIE has been set, another cpu may release_task (NULLifying p->signal) in between account_system_time's check and check_rlimit's dereference. Nor should account_it_prof risk send_sig. But surely account_user_time is safe? Signed-off-by: Hugh Dickins Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/parisc/kernel/binfmt_elf32.c | 6 +- arch/ppc64/kernel/binfmt_elf32.c | 6 +- arch/s390/kernel/binfmt_elf32.c | 6 +- arch/sparc64/kernel/binfmt_elf32.c | 6 +- fs/binfmt_elf.c | 12 +-- fs/proc/array.c | 22 ++--- fs/proc/proc_misc.c | 60 +++++++------ include/asm-alpha/cputime.h | 6 ++ include/asm-arm/cputime.h | 6 ++ include/asm-arm26/cputime.h | 6 ++ include/asm-cris/cputime.h | 6 ++ include/asm-generic/cputime.h | 64 ++++++++++++++ include/asm-h8300/cputime.h | 6 ++ include/asm-i386/cputime.h | 6 ++ include/asm-ia64/cputime.h | 6 ++ include/asm-m32r/cputime.h | 6 ++ include/asm-m68k/cputime.h | 6 ++ include/asm-m68knommu/cputime.h | 6 ++ include/asm-mips/cputime.h | 6 ++ include/asm-parisc/cputime.h | 6 ++ include/asm-ppc/cputime.h | 6 ++ include/asm-ppc64/cputime.h | 6 ++ include/asm-s390/cputime.h | 6 ++ include/asm-sh/cputime.h | 6 ++ include/asm-sh64/cputime.h | 6 ++ include/asm-sparc/cputime.h | 6 ++ include/asm-sparc64/cputime.h | 6 ++ include/asm-um/cputime.h | 6 ++ include/asm-v850/cputime.h | 6 ++ include/asm-x86_64/cputime.h | 6 ++ include/linux/kernel_stat.h | 20 +++-- include/linux/sched.h | 12 +-- kernel/compat.c | 14 ++-- kernel/cpu.c | 4 +- kernel/exit.c | 18 ++-- kernel/fork.c | 14 ++-- kernel/itimer.c | 57 +++++++------ kernel/sched.c | 168 +++++++++++++++++++++++++++++++------ kernel/signal.c | 14 ++-- kernel/sys.c | 34 ++++---- kernel/timer.c | 65 ++------------ mm/oom_kill.c | 3 +- 42 files changed, 523 insertions(+), 214 deletions(-) create mode 100644 include/asm-alpha/cputime.h create mode 100644 include/asm-arm/cputime.h create mode 100644 include/asm-arm26/cputime.h create mode 100644 include/asm-cris/cputime.h create mode 100644 include/asm-generic/cputime.h create mode 100644 include/asm-h8300/cputime.h create mode 100644 include/asm-i386/cputime.h create mode 100644 include/asm-ia64/cputime.h create mode 100644 include/asm-m32r/cputime.h create mode 100644 include/asm-m68k/cputime.h create mode 100644 include/asm-m68knommu/cputime.h create mode 100644 include/asm-mips/cputime.h create mode 100644 include/asm-parisc/cputime.h create mode 100644 include/asm-ppc/cputime.h create mode 100644 include/asm-ppc64/cputime.h create mode 100644 include/asm-s390/cputime.h create mode 100644 include/asm-sh/cputime.h create mode 100644 include/asm-sh64/cputime.h create mode 100644 include/asm-sparc/cputime.h create mode 100644 include/asm-sparc64/cputime.h create mode 100644 include/asm-um/cputime.h create mode 100644 include/asm-v850/cputime.h create mode 100644 include/asm-x86_64/cputime.h (limited to 'include/linux') diff --git a/arch/parisc/kernel/binfmt_elf32.c b/arch/parisc/kernel/binfmt_elf32.c index 4486a745b0ef..6fd07e90aad7 100644 --- a/arch/parisc/kernel/binfmt_elf32.c +++ b/arch/parisc/kernel/binfmt_elf32.c @@ -92,10 +92,12 @@ struct elf_prpsinfo32 current->thread.map_base = DEFAULT_MAP_BASE32; \ current->thread.task_size = DEFAULT_TASK_SIZE32 \ -#define jiffies_to_timeval jiffies_to_compat_timeval +#undef cputime_to_timeval +#define cputime_to_timeval cputime_to_compat_timeval static __inline__ void -jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) +cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) { + unsigned long jiffies = cputime_to_jiffies(cputime); value->tv_usec = (jiffies % HZ) * (1000000L / HZ); value->tv_sec = jiffies / HZ; } diff --git a/arch/ppc64/kernel/binfmt_elf32.c b/arch/ppc64/kernel/binfmt_elf32.c index 478e5fce6be1..fadc699a0497 100644 --- a/arch/ppc64/kernel/binfmt_elf32.c +++ b/arch/ppc64/kernel/binfmt_elf32.c @@ -60,10 +60,12 @@ struct elf_prpsinfo32 #include -#define jiffies_to_timeval jiffies_to_compat_timeval +#undef cputime_to_timeval +#define cputime_to_timeval cputime_to_compat_timeval static __inline__ void -jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) +cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) { + unsigned long jiffies = cputime_to_jiffies(cputime); value->tv_usec = (jiffies % HZ) * (1000000L / HZ); value->tv_sec = jiffies / HZ; } diff --git a/arch/s390/kernel/binfmt_elf32.c b/arch/s390/kernel/binfmt_elf32.c index 1100c409b5bb..ed234bf06d1c 100644 --- a/arch/s390/kernel/binfmt_elf32.c +++ b/arch/s390/kernel/binfmt_elf32.c @@ -197,10 +197,12 @@ MODULE_AUTHOR("Gerhard Tonn "); #undef MODULE_DESCRIPTION #undef MODULE_AUTHOR -#define jiffies_to_timeval jiffies_to_compat_timeval +#undef cputime_to_timeval +#define cputime_to_timeval cputime_to_compat_timeval static __inline__ void -jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) +cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) { + unsigned long jiffies = cputime_to_jiffies(cputime); value->tv_usec = (jiffies % HZ) * (1000000L / HZ); value->tv_sec = jiffies / HZ; } diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c index c13eaf030758..a1a12d2aa353 100644 --- a/arch/sparc64/kernel/binfmt_elf32.c +++ b/arch/sparc64/kernel/binfmt_elf32.c @@ -132,10 +132,12 @@ struct elf_prpsinfo32 #include -#define jiffies_to_timeval jiffies_to_compat_timeval +#undef cputime_to_timeval +#define cputime_to_timeval cputime_to_compat_timeval static __inline__ void -jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) +cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) { + unsigned long jiffies = cputime_to_jiffies(cputime); value->tv_usec = (jiffies % HZ) * (1000000L / HZ); value->tv_sec = jiffies / HZ; } diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 0ecc44fb0551..eaa2c7026e60 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1215,16 +1215,16 @@ static void fill_prstatus(struct elf_prstatus *prstatus, * this and each other thread to finish dying after the * core dump synchronization phase. */ - jiffies_to_timeval(p->utime + p->signal->utime, + cputime_to_timeval(cputime_add(p->utime, p->signal->utime), &prstatus->pr_utime); - jiffies_to_timeval(p->stime + p->signal->stime, + cputime_to_timeval(cputime_add(p->stime, p->signal->stime), &prstatus->pr_stime); } else { - jiffies_to_timeval(p->utime, &prstatus->pr_utime); - jiffies_to_timeval(p->stime, &prstatus->pr_stime); + cputime_to_timeval(p->utime, &prstatus->pr_utime); + cputime_to_timeval(p->stime, &prstatus->pr_stime); } - jiffies_to_timeval(p->signal->cutime, &prstatus->pr_cutime); - jiffies_to_timeval(p->signal->cstime, &prstatus->pr_cstime); + cputime_to_timeval(p->signal->cutime, &prstatus->pr_cutime); + cputime_to_timeval(p->signal->cstime, &prstatus->pr_cstime); } static void fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, diff --git a/fs/proc/array.c b/fs/proc/array.c index e4bd14aa005d..eb5c084ede4a 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -313,8 +313,9 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) int num_threads = 0; struct mm_struct *mm; unsigned long long start_time; - unsigned long cmin_flt = 0, cmaj_flt = 0, cutime = 0, cstime = 0; - unsigned long min_flt = 0, maj_flt = 0, utime = 0, stime = 0; + unsigned long cmin_flt = 0, cmaj_flt = 0; + unsigned long min_flt = 0, maj_flt = 0; + cputime_t cutime, cstime, utime, stime; unsigned long rsslim = 0; struct task_struct *t; char tcomm[sizeof(task->comm)]; @@ -332,6 +333,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) sigemptyset(&sigign); sigemptyset(&sigcatch); + cutime = cstime = utime = stime = cputime_zero; read_lock(&tasklist_lock); if (task->sighand) { spin_lock_irq(&task->sighand->siglock); @@ -344,8 +346,8 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) do { min_flt += t->min_flt; maj_flt += t->maj_flt; - utime += t->utime; - stime += t->stime; + utime = cputime_add(utime, t->utime); + stime = cputime_add(stime, t->stime); t = next_thread(t); } while (t != task); } @@ -367,8 +369,8 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) if (whole) { min_flt += task->signal->min_flt; maj_flt += task->signal->maj_flt; - utime += task->signal->utime; - stime += task->signal->stime; + utime = cputime_add(utime, task->signal->utime); + stime = cputime_add(stime, task->signal->stime); } } ppid = pid_alive(task) ? task->group_leader->real_parent->tgid : 0; @@ -411,10 +413,10 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) cmin_flt, maj_flt, cmaj_flt, - jiffies_to_clock_t(utime), - jiffies_to_clock_t(stime), - jiffies_to_clock_t(cutime), - jiffies_to_clock_t(cstime), + cputime_to_clock_t(utime), + cputime_to_clock_t(stime), + cputime_to_clock_t(cutime), + cputime_to_clock_t(cstime), priority, nice, num_threads, diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index c7322cfefe13..89d09007df5d 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -101,10 +101,10 @@ static int uptime_read_proc(char *page, char **start, off_t off, struct timespec uptime; struct timespec idle; int len; - u64 idle_jiffies = init_task.utime + init_task.stime; + cputime_t idletime = cputime_add(init_task.utime, init_task.stime); do_posix_clock_monotonic_gettime(&uptime); - jiffies_to_timespec(idle_jiffies, &idle); + cputime_to_timespec(idletime, &idle); len = sprintf(page,"%lu.%02lu %lu.%02lu\n", (unsigned long) uptime.tv_sec, (uptime.tv_nsec / (NSEC_PER_SEC / 100)), @@ -322,9 +322,11 @@ static int show_stat(struct seq_file *p, void *v) { int i; unsigned long jif; - u64 sum = 0, user = 0, nice = 0, system = 0, - idle = 0, iowait = 0, irq = 0, softirq = 0; + cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; + u64 sum = 0; + user = nice = system = idle = iowait = + irq = softirq = steal = cputime64_zero; jif = - wall_to_monotonic.tv_sec; if (wall_to_monotonic.tv_nsec) --jif; @@ -332,25 +334,27 @@ static int show_stat(struct seq_file *p, void *v) for_each_cpu(i) { int j; - user += kstat_cpu(i).cpustat.user; - nice += kstat_cpu(i).cpustat.nice; - system += kstat_cpu(i).cpustat.system; - idle += kstat_cpu(i).cpustat.idle; - iowait += kstat_cpu(i).cpustat.iowait; - irq += kstat_cpu(i).cpustat.irq; - softirq += kstat_cpu(i).cpustat.softirq; + user = cputime64_add(user, kstat_cpu(i).cpustat.user); + nice = cputime64_add(nice, kstat_cpu(i).cpustat.nice); + system = cputime64_add(system, kstat_cpu(i).cpustat.system); + idle = cputime64_add(idle, kstat_cpu(i).cpustat.idle); + iowait = cputime64_add(iowait, kstat_cpu(i).cpustat.iowait); + irq = cputime64_add(irq, kstat_cpu(i).cpustat.irq); + softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq); + steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal); for (j = 0 ; j < NR_IRQS ; j++) sum += kstat_cpu(i).irqs[j]; } - seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu\n", - (unsigned long long)jiffies_64_to_clock_t(user), - (unsigned long long)jiffies_64_to_clock_t(nice), - (unsigned long long)jiffies_64_to_clock_t(system), - (unsigned long long)jiffies_64_to_clock_t(idle), - (unsigned long long)jiffies_64_to_clock_t(iowait), - (unsigned long long)jiffies_64_to_clock_t(irq), - (unsigned long long)jiffies_64_to_clock_t(softirq)); + seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu\n", + (unsigned long long)cputime64_to_clock_t(user), + (unsigned long long)cputime64_to_clock_t(nice), + (unsigned long long)cputime64_to_clock_t(system), + (unsigned long long)cputime64_to_clock_t(idle), + (unsigned long long)cputime64_to_clock_t(iowait), + (unsigned long long)cputime64_to_clock_t(irq), + (unsigned long long)cputime64_to_clock_t(softirq), + (unsigned long long)cputime64_to_clock_t(steal)); for_each_online_cpu(i) { /* Copy values here to work around gcc-2.95.3, gcc-2.96 */ @@ -361,15 +365,17 @@ static int show_stat(struct seq_file *p, void *v) iowait = kstat_cpu(i).cpustat.iowait; irq = kstat_cpu(i).cpustat.irq; softirq = kstat_cpu(i).cpustat.softirq; - seq_printf(p, "cpu%d %llu %llu %llu %llu %llu %llu %llu\n", + steal = kstat_cpu(i).cpustat.steal; + seq_printf(p, "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu\n", i, - (unsigned long long)jiffies_64_to_clock_t(user), - (unsigned long long)jiffies_64_to_clock_t(nice), - (unsigned long long)jiffies_64_to_clock_t(system), - (unsigned long long)jiffies_64_to_clock_t(idle), - (unsigned long long)jiffies_64_to_clock_t(iowait), - (unsigned long long)jiffies_64_to_clock_t(irq), - (unsigned long long)jiffies_64_to_clock_t(softirq)); + (unsigned long long)cputime64_to_clock_t(user), + (unsigned long long)cputime64_to_clock_t(nice), + (unsigned long long)cputime64_to_clock_t(system), + (unsigned long long)cputime64_to_clock_t(idle), + (unsigned long long)cputime64_to_clock_t(iowait), + (unsigned long long)cputime64_to_clock_t(irq), + (unsigned long long)cputime64_to_clock_t(softirq), + (unsigned long long)cputime64_to_clock_t(steal)); } seq_printf(p, "intr %llu", (unsigned long long)sum); diff --git a/include/asm-alpha/cputime.h b/include/asm-alpha/cputime.h new file mode 100644 index 000000000000..19577fd93230 --- /dev/null +++ b/include/asm-alpha/cputime.h @@ -0,0 +1,6 @@ +#ifndef __ALPHA_CPUTIME_H +#define __ALPHA_CPUTIME_H + +#include + +#endif /* __ALPHA_CPUTIME_H */ diff --git a/include/asm-arm/cputime.h b/include/asm-arm/cputime.h new file mode 100644 index 000000000000..3a8002a5fec7 --- /dev/null +++ b/include/asm-arm/cputime.h @@ -0,0 +1,6 @@ +#ifndef __ARM_CPUTIME_H +#define __ARM_CPUTIME_H + +#include + +#endif /* __ARM_CPUTIME_H */ diff --git a/include/asm-arm26/cputime.h b/include/asm-arm26/cputime.h new file mode 100644 index 000000000000..d2783a9e47b3 --- /dev/null +++ b/include/asm-arm26/cputime.h @@ -0,0 +1,6 @@ +#ifndef __ARM26_CPUTIME_H +#define __ARM26_CPUTIME_H + +#include + +#endif /* __ARM26_CPUTIME_H */ diff --git a/include/asm-cris/cputime.h b/include/asm-cris/cputime.h new file mode 100644 index 000000000000..4446a65656fa --- /dev/null +++ b/include/asm-cris/cputime.h @@ -0,0 +1,6 @@ +#ifndef __CRIS_CPUTIME_H +#define __CRIS_CPUTIME_H + +#include + +#endif /* __CRIS_CPUTIME_H */ diff --git a/include/asm-generic/cputime.h b/include/asm-generic/cputime.h new file mode 100644 index 000000000000..c9968a09f8ab --- /dev/null +++ b/include/asm-generic/cputime.h @@ -0,0 +1,64 @@ +#ifndef _ASM_GENERIC_CPUTIME_H +#define _ASM_GENERIC_CPUTIME_H + +#include +#include + +typedef unsigned long cputime_t; + +#define cputime_zero (0UL) +#define cputime_max ((~0UL >> 1) - 1) +#define cputime_add(__a, __b) ((__a) + (__b)) +#define cputime_sub(__a, __b) ((__a) - (__b)) +#define cputime_eq(__a, __b) ((__a) == (__b)) +#define cputime_gt(__a, __b) ((__a) > (__b)) +#define cputime_ge(__a, __b) ((__a) >= (__b)) +#define cputime_lt(__a, __b) ((__a) < (__b)) +#define cputime_le(__a, __b) ((__a) <= (__b)) +#define cputime_to_jiffies(__ct) (__ct) +#define jiffies_to_cputime(__hz) (__hz) + +typedef u64 cputime64_t; + +#define cputime64_zero (0ULL) +#define cputime64_add(__a, __b) ((__a) + (__b)) +#define cputime64_to_jiffies64(__ct) (__ct) +#define cputime_to_cputime64(__ct) ((u64) __ct) + + +/* + * Convert cputime to milliseconds and back. + */ +#define cputime_to_msecs(__ct) jiffies_to_msecs(__ct) +#define msecs_to_cputime(__msecs) msecs_to_jiffies(__msecs) + +/* + * Convert cputime to seconds and back. + */ +#define cputime_to_secs(__ct) (jiffies_to_msecs(__ct) / HZ) +#define secs_to_cputime(__secs) (msecs_to_jiffies(__secs * HZ)) + +/* + * Convert cputime to timespec and back. + */ +#define timespec_to_cputime(__val) timespec_to_jiffies(__val) +#define cputime_to_timespec(__ct,__val) jiffies_to_timespec(__ct,__val) + +/* + * Convert cputime to timeval and back. + */ +#define timeval_to_cputime(__val) timeval_to_jiffies(__val) +#define cputime_to_timeval(__ct,__val) jiffies_to_timeval(__ct,__val) + +/* + * Convert cputime to clock and back. + */ +#define cputime_to_clock_t(__ct) jiffies_to_clock_t(__ct) +#define clock_t_to_cputime(__x) clock_t_to_jiffies(__x) + +/* + * Convert cputime64 to clock. + */ +#define cputime64_to_clock_t(__ct) jiffies_64_to_clock_t(__ct) + +#endif diff --git a/include/asm-h8300/cputime.h b/include/asm-h8300/cputime.h new file mode 100644 index 000000000000..092e187c7b08 --- /dev/null +++ b/include/asm-h8300/cputime.h @@ -0,0 +1,6 @@ +#ifndef __H8300_CPUTIME_H +#define __H8300_CPUTIME_H + +#include + +#endif /* __H8300_CPUTIME_H */ diff --git a/include/asm-i386/cputime.h b/include/asm-i386/cputime.h new file mode 100644 index 000000000000..398ed7cd171d --- /dev/null +++ b/include/asm-i386/cputime.h @@ -0,0 +1,6 @@ +#ifndef __I386_CPUTIME_H +#define __I386_CPUTIME_H + +#include + +#endif /* __I386_CPUTIME_H */ diff --git a/include/asm-ia64/cputime.h b/include/asm-ia64/cputime.h new file mode 100644 index 000000000000..72400a78002a --- /dev/null +++ b/include/asm-ia64/cputime.h @@ -0,0 +1,6 @@ +#ifndef __IA64_CPUTIME_H +#define __IA64_CPUTIME_H + +#include + +#endif /* __IA64_CPUTIME_H */ diff --git a/include/asm-m32r/cputime.h b/include/asm-m32r/cputime.h new file mode 100644 index 000000000000..0a47550df2b7 --- /dev/null +++ b/include/asm-m32r/cputime.h @@ -0,0 +1,6 @@ +#ifndef __M32R_CPUTIME_H +#define __M32R_CPUTIME_H + +#include + +#endif /* __M32R_CPUTIME_H */ diff --git a/include/asm-m68k/cputime.h b/include/asm-m68k/cputime.h new file mode 100644 index 000000000000..c79c5e892305 --- /dev/null +++ b/include/asm-m68k/cputime.h @@ -0,0 +1,6 @@ +#ifndef __M68K_CPUTIME_H +#define __M68K_CPUTIME_H + +#include + +#endif /* __M68K_CPUTIME_H */ diff --git a/include/asm-m68knommu/cputime.h b/include/asm-m68knommu/cputime.h new file mode 100644 index 000000000000..a0c4a660878d --- /dev/null +++ b/include/asm-m68knommu/cputime.h @@ -0,0 +1,6 @@ +#ifndef __M68KNOMMU_CPUTIME_H +#define __M68KNOMMU_CPUTIME_H + +#include + +#endif /* __M68KNOMMU_CPUTIME_H */ diff --git a/include/asm-mips/cputime.h b/include/asm-mips/cputime.h new file mode 100644 index 000000000000..c00eacbdd979 --- /dev/null +++ b/include/asm-mips/cputime.h @@ -0,0 +1,6 @@ +#ifndef __MIPS_CPUTIME_H +#define __MIPS_CPUTIME_H + +#include + +#endif /* __MIPS_CPUTIME_H */ diff --git a/include/asm-parisc/cputime.h b/include/asm-parisc/cputime.h new file mode 100644 index 000000000000..dcdf2fbd7e72 --- /dev/null +++ b/include/asm-parisc/cputime.h @@ -0,0 +1,6 @@ +#ifndef __PARISC_CPUTIME_H +#define __PARISC_CPUTIME_H + +#include + +#endif /* __PARISC_CPUTIME_H */ diff --git a/include/asm-ppc/cputime.h b/include/asm-ppc/cputime.h new file mode 100644 index 000000000000..8e9faf5ce720 --- /dev/null +++ b/include/asm-ppc/cputime.h @@ -0,0 +1,6 @@ +#ifndef __PPC_CPUTIME_H +#define __PPC_CPUTIME_H + +#include + +#endif /* __PPC_CPUTIME_H */ diff --git a/include/asm-ppc64/cputime.h b/include/asm-ppc64/cputime.h new file mode 100644 index 000000000000..8e9faf5ce720 --- /dev/null +++ b/include/asm-ppc64/cputime.h @@ -0,0 +1,6 @@ +#ifndef __PPC_CPUTIME_H +#define __PPC_CPUTIME_H + +#include + +#endif /* __PPC_CPUTIME_H */ diff --git a/include/asm-s390/cputime.h b/include/asm-s390/cputime.h new file mode 100644 index 000000000000..ad989e5d369c --- /dev/null +++ b/include/asm-s390/cputime.h @@ -0,0 +1,6 @@ +#ifndef __S390_CPUTIME_H +#define __S390_CPUTIME_H + +#include + +#endif /* __S390_CPUTIME_H */ diff --git a/include/asm-sh/cputime.h b/include/asm-sh/cputime.h new file mode 100644 index 000000000000..6ca395d1393e --- /dev/null +++ b/include/asm-sh/cputime.h @@ -0,0 +1,6 @@ +#ifndef __SH_CPUTIME_H +#define __SH_CPUTIME_H + +#include + +#endif /* __SH_CPUTIME_H */ diff --git a/include/asm-sh64/cputime.h b/include/asm-sh64/cputime.h new file mode 100644 index 000000000000..0fd89da2aa86 --- /dev/null +++ b/include/asm-sh64/cputime.h @@ -0,0 +1,6 @@ +#ifndef __SH64_CPUTIME_H +#define __SH64_CPUTIME_H + +#include + +#endif /* __SH64_CPUTIME_H */ diff --git a/include/asm-sparc/cputime.h b/include/asm-sparc/cputime.h new file mode 100644 index 000000000000..1a642b81e019 --- /dev/null +++ b/include/asm-sparc/cputime.h @@ -0,0 +1,6 @@ +#ifndef __SPARC_CPUTIME_H +#define __SPARC_CPUTIME_H + +#include + +#endif /* __SPARC_CPUTIME_H */ diff --git a/include/asm-sparc64/cputime.h b/include/asm-sparc64/cputime.h new file mode 100644 index 000000000000..dec2fc7a36f8 --- /dev/null +++ b/include/asm-sparc64/cputime.h @@ -0,0 +1,6 @@ +#ifndef __SPARC64_CPUTIME_H +#define __SPARC64_CPUTIME_H + +#include + +#endif /* __SPARC64_CPUTIME_H */ diff --git a/include/asm-um/cputime.h b/include/asm-um/cputime.h new file mode 100644 index 000000000000..c84acbadfa2f --- /dev/null +++ b/include/asm-um/cputime.h @@ -0,0 +1,6 @@ +#ifndef __UM_CPUTIME_H +#define __UM_CPUTIME_H + +#include + +#endif /* __UM_CPUTIME_H */ diff --git a/include/asm-v850/cputime.h b/include/asm-v850/cputime.h new file mode 100644 index 000000000000..7c799c33b8a9 --- /dev/null +++ b/include/asm-v850/cputime.h @@ -0,0 +1,6 @@ +#ifndef __V850_CPUTIME_H +#define __V850_CPUTIME_H + +#include + +#endif /* __V850_CPUTIME_H */ diff --git a/include/asm-x86_64/cputime.h b/include/asm-x86_64/cputime.h new file mode 100644 index 000000000000..a07012dc5a3c --- /dev/null +++ b/include/asm-x86_64/cputime.h @@ -0,0 +1,6 @@ +#ifndef __X86_64_CPUTIME_H +#define __X86_64_CPUTIME_H + +#include + +#endif /* __X86_64_CPUTIME_H */ diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index 4594ccc4a7c1..dba27749b428 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h @@ -6,6 +6,7 @@ #include #include #include +#include /* * 'kernel_stat.h' contains the definitions needed for doing @@ -14,13 +15,14 @@ */ struct cpu_usage_stat { - u64 user; - u64 nice; - u64 system; - u64 softirq; - u64 irq; - u64 idle; - u64 iowait; + cputime64_t user; + cputime64_t nice; + cputime64_t system; + cputime64_t softirq; + cputime64_t irq; + cputime64_t idle; + cputime64_t iowait; + cputime64_t steal; }; struct kernel_stat { @@ -50,4 +52,8 @@ static inline int kstat_irqs(int irq) return sum; } +extern void account_user_time(struct task_struct *, cputime_t); +extern void account_system_time(struct task_struct *, int, cputime_t); +extern void account_steal_time(struct task_struct *, cputime_t); + #endif /* _LINUX_KERNEL_STAT_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 3c2c63f23a4a..dcc1814f97e8 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -168,7 +169,7 @@ long io_schedule_timeout(long timeout); extern void cpu_init (void); extern void trap_init(void); extern void update_process_times(int user); -extern void scheduler_tick(int user_tick, int system); +extern void scheduler_tick(void); extern unsigned long cache_decay_ticks; /* Attach to any functions which should be ignored in wchan output. */ @@ -311,7 +312,7 @@ struct signal_struct { * Live threads maintain their own counters and add to these * in __exit_signal, except for the group leader. */ - unsigned long utime, stime, cutime, cstime; + cputime_t utime, stime, cutime, cstime; unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw; unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt; @@ -589,10 +590,11 @@ struct task_struct { int __user *clear_child_tid; /* CLONE_CHILD_CLEARTID */ unsigned long rt_priority; - unsigned long it_real_value, it_prof_value, it_virt_value; - unsigned long it_real_incr, it_prof_incr, it_virt_incr; + unsigned long it_real_value, it_real_incr; + cputime_t it_virt_value, it_virt_incr; + cputime_t it_prof_value, it_prof_incr; struct timer_list real_timer; - unsigned long utime, stime; + cputime_t utime, stime; unsigned long nvcsw, nivcsw; /* context switch counts */ struct timespec start_time; /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */ diff --git a/kernel/compat.c b/kernel/compat.c index 48ee147c1343..d1b1d4dd019a 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -163,15 +163,15 @@ asmlinkage long compat_sys_times(struct compat_tms __user *tbuf) struct compat_tms tmp; struct task_struct *tsk = current; struct task_struct *t; - unsigned long utime, stime, cutime, cstime; + cputime_t utime, stime, cutime, cstime; read_lock(&tasklist_lock); utime = tsk->signal->utime; stime = tsk->signal->stime; t = tsk; do { - utime += t->utime; - stime += t->stime; + utime = cputime_add(utime, t->utime); + stime = cputime_add(stime, t->stime); t = next_thread(t); } while (t != tsk); @@ -190,10 +190,10 @@ asmlinkage long compat_sys_times(struct compat_tms __user *tbuf) spin_unlock_irq(&tsk->sighand->siglock); read_unlock(&tasklist_lock); - tmp.tms_utime = compat_jiffies_to_clock_t(utime); - tmp.tms_stime = compat_jiffies_to_clock_t(stime); - tmp.tms_cutime = compat_jiffies_to_clock_t(cutime); - tmp.tms_cstime = compat_jiffies_to_clock_t(cstime); + tmp.tms_utime = compat_jiffies_to_clock_t(cputime_to_jiffies(utime)); + tmp.tms_stime = compat_jiffies_to_clock_t(cputime_to_jiffies(stime)); + tmp.tms_cutime = compat_jiffies_to_clock_t(cputime_to_jiffies(cutime)); + tmp.tms_cstime = compat_jiffies_to_clock_t(cputime_to_jiffies(cstime)); if (copy_to_user(tbuf, &tmp, sizeof(tmp))) return -EFAULT; } diff --git a/kernel/cpu.c b/kernel/cpu.c index b97f7f91ec6d..628f4ccda127 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -48,7 +48,9 @@ static inline void check_for_tasks(int cpu) write_lock_irq(&tasklist_lock); for_each_process(p) { - if (task_cpu(p) == cpu && (p->utime != 0 || p->stime != 0)) + if (task_cpu(p) == cpu && + (!cputime_eq(p->utime, cputime_zero) || + !cputime_eq(p->stime, cputime_zero))) printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d\ (state = %ld, flags = %lx) \n", p->comm, p->pid, cpu, p->state, p->flags); diff --git a/kernel/exit.c b/kernel/exit.c index 02f0a95cb557..e0df301a4553 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -755,8 +755,8 @@ static void exit_notify(struct task_struct *tsk) * Clear these here so that update_process_times() won't try to deliver * itimer, profile or rlimit signals to this task while it is in late exit. */ - tsk->it_virt_value = 0; - tsk->it_prof_value = 0; + tsk->it_virt_value = cputime_zero; + tsk->it_prof_value = cputime_zero; write_unlock_irq(&tasklist_lock); @@ -1046,10 +1046,16 @@ static int wait_task_zombie(task_t *p, int noreap, * here reaping other children at the same time. */ spin_lock_irq(&p->parent->sighand->siglock); - p->parent->signal->cutime += - p->utime + p->signal->utime + p->signal->cutime; - p->parent->signal->cstime += - p->stime + p->signal->stime + p->signal->cstime; + p->parent->signal->cutime = + cputime_add(p->parent->signal->cutime, + cputime_add(p->utime, + cputime_add(p->signal->utime, + p->signal->cutime))); + p->parent->signal->cstime = + cputime_add(p->parent->signal->cstime, + cputime_add(p->stime, + cputime_add(p->signal->stime, + p->signal->cstime))); p->parent->signal->cmin_flt += p->min_flt + p->signal->min_flt + p->signal->cmin_flt; p->parent->signal->cmaj_flt += diff --git a/kernel/fork.c b/kernel/fork.c index 6d9412937d37..be1ff8ddbb9c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -749,7 +749,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts sig->leader = 0; /* session leadership doesn't inherit */ sig->tty_old_pgrp = 0; - sig->utime = sig->stime = sig->cutime = sig->cstime = 0; + sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero; sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0; sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0; @@ -871,15 +871,15 @@ static task_t *copy_process(unsigned long clone_flags, p->it_real_value = 0; p->it_real_incr = 0; - p->it_virt_value = 0; - p->it_virt_incr = 0; - p->it_prof_value = 0; - p->it_prof_incr = 0; + p->it_virt_value = cputime_zero; + p->it_virt_incr = cputime_zero; + p->it_prof_value = cputime_zero; + p->it_prof_incr = cputime_zero; init_timer(&p->real_timer); p->real_timer.data = (unsigned long) p; - p->utime = 0; - p->stime = 0; + p->utime = cputime_zero; + p->stime = cputime_zero; p->rchar = 0; /* I/O counter: bytes read */ p->wchar = 0; /* I/O counter: bytes written */ p->syscr = 0; /* I/O counter: read syscalls */ diff --git a/kernel/itimer.c b/kernel/itimer.c index 95fbf1c6becf..e1743c563206 100644 --- a/kernel/itimer.c +++ b/kernel/itimer.c @@ -16,11 +16,10 @@ int do_getitimer(int which, struct itimerval *value) { - register unsigned long val, interval; + register unsigned long val; switch (which) { case ITIMER_REAL: - interval = current->it_real_incr; val = 0; /* * FIXME! This needs to be atomic, in case the kernel timer happens! @@ -32,20 +31,20 @@ int do_getitimer(int which, struct itimerval *value) if ((long) val <= 0) val = 1; } + jiffies_to_timeval(val, &value->it_value); + jiffies_to_timeval(current->it_real_incr, &value->it_interval); break; case ITIMER_VIRTUAL: - val = current->it_virt_value; - interval = current->it_virt_incr; + cputime_to_timeval(current->it_virt_value, &value->it_value); + cputime_to_timeval(current->it_virt_incr, &value->it_interval); break; case ITIMER_PROF: - val = current->it_prof_value; - interval = current->it_prof_incr; + cputime_to_timeval(current->it_prof_value, &value->it_value); + cputime_to_timeval(current->it_prof_incr, &value->it_interval); break; default: return(-EINVAL); } - jiffies_to_timeval(val, &value->it_value); - jiffies_to_timeval(interval, &value->it_interval); return 0; } @@ -81,37 +80,43 @@ void it_real_fn(unsigned long __data) int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) { - register unsigned long i, j; + unsigned long expire; + cputime_t cputime; int k; - i = timeval_to_jiffies(&value->it_interval); - j = timeval_to_jiffies(&value->it_value); if (ovalue && (k = do_getitimer(which, ovalue)) < 0) return k; switch (which) { case ITIMER_REAL: del_timer_sync(¤t->real_timer); - current->it_real_value = j; - current->it_real_incr = i; - if (!j) + expire = timeval_to_jiffies(&value->it_value); + current->it_real_value = expire; + current->it_real_incr = + timeval_to_jiffies(&value->it_interval); + if (!expire) break; - if (j > (unsigned long) LONG_MAX) - j = LONG_MAX; - i = j + jiffies; - current->real_timer.expires = i; + if (expire > (unsigned long) LONG_MAX) + expire = LONG_MAX; + current->real_timer.expires = jiffies + expire; add_timer(¤t->real_timer); break; case ITIMER_VIRTUAL: - if (j) - j++; - current->it_virt_value = j; - current->it_virt_incr = i; + cputime = timeval_to_cputime(&value->it_value); + if (cputime_gt(cputime, cputime_zero)) + cputime = cputime_add(cputime, + jiffies_to_cputime(1)); + current->it_virt_value = cputime; + cputime = timeval_to_cputime(&value->it_interval); + current->it_virt_incr = cputime; break; case ITIMER_PROF: - if (j) - j++; - current->it_prof_value = j; - current->it_prof_incr = i; + cputime = timeval_to_cputime(&value->it_value); + if (cputime_gt(cputime, cputime_zero)) + cputime = cputime_add(cputime, + jiffies_to_cputime(1)); + current->it_prof_value = cputime; + cputime = timeval_to_cputime(&value->it_interval); + current->it_prof_incr = cputime; break; default: return -EINVAL; diff --git a/kernel/sched.c b/kernel/sched.c index 1c523337bc61..9e1fbc42bd01 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1182,7 +1182,7 @@ void fastcall sched_fork(task_t *p) */ current->time_slice = 1; preempt_disable(); - scheduler_tick(0, 0); + scheduler_tick(); local_irq_enable(); preempt_enable(); } else @@ -2250,6 +2250,148 @@ EXPORT_PER_CPU_SYMBOL(kstat); STARVATION_LIMIT * ((rq)->nr_running) + 1))) || \ ((rq)->curr->static_prio > (rq)->best_expired_prio)) +/* + * Do the virtual cpu time signal calculations. + * @p: the process that the cpu time gets accounted to + * @cputime: the cpu time spent in user space since the last update + */ +static inline void account_it_virt(struct task_struct * p, cputime_t cputime) +{ + cputime_t it_virt = p->it_virt_value; + + if (cputime_gt(it_virt, cputime_zero) && + cputime_gt(cputime, cputime_zero)) { + if (cputime_ge(cputime, it_virt)) { + it_virt = cputime_add(it_virt, p->it_virt_incr); + send_sig(SIGVTALRM, p, 1); + } + it_virt = cputime_sub(it_virt, cputime); + p->it_virt_value = it_virt; + } +} + +/* + * Do the virtual profiling signal calculations. + * @p: the process that the cpu time gets accounted to + * @cputime: the cpu time spent in user and kernel space since the last update + */ +static void account_it_prof(struct task_struct *p, cputime_t cputime) +{ + cputime_t it_prof = p->it_prof_value; + + if (cputime_gt(it_prof, cputime_zero) && + cputime_gt(cputime, cputime_zero)) { + if (cputime_ge(cputime, it_prof)) { + it_prof = cputime_add(it_prof, p->it_prof_incr); + send_sig(SIGPROF, p, 1); + } + it_prof = cputime_sub(it_prof, cputime); + p->it_prof_value = it_prof; + } +} + +/* + * Check if the process went over its cputime resource limit after + * some cpu time got added to utime/stime. + * @p: the process that the cpu time gets accounted to + * @cputime: the cpu time spent in user and kernel space since the last update + */ +static void check_rlimit(struct task_struct *p, cputime_t cputime) +{ + cputime_t total, tmp; + + total = cputime_add(p->utime, p->stime); + tmp = jiffies_to_cputime(p->signal->rlim[RLIMIT_CPU].rlim_cur); + if (unlikely(cputime_gt(total, tmp))) { + /* Send SIGXCPU every second. */ + tmp = cputime_sub(total, cputime); + if (cputime_to_secs(tmp) < cputime_to_secs(total)) + send_sig(SIGXCPU, p, 1); + /* and SIGKILL when we go over max.. */ + tmp = jiffies_to_cputime(p->signal->rlim[RLIMIT_CPU].rlim_max); + if (cputime_gt(total, tmp)) + send_sig(SIGKILL, p, 1); + } +} + +/* + * Account user cpu time to a process. + * @p: the process that the cpu time gets accounted to + * @hardirq_offset: the offset to subtract from hardirq_count() + * @cputime: the cpu time spent in user space since the last update + */ +void account_user_time(struct task_struct *p, cputime_t cputime) +{ + struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat; + cputime64_t tmp; + + p->utime = cputime_add(p->utime, cputime); + + /* Check for signals (SIGVTALRM, SIGPROF, SIGXCPU & SIGKILL). */ + check_rlimit(p, cputime); + account_it_virt(p, cputime); + account_it_prof(p, cputime); + + /* Add user time to cpustat. */ + tmp = cputime_to_cputime64(cputime); + if (TASK_NICE(p) > 0) + cpustat->nice = cputime64_add(cpustat->nice, tmp); + else + cpustat->user = cputime64_add(cpustat->user, tmp); +} + +/* + * Account system cpu time to a process. + * @p: the process that the cpu time gets accounted to + * @hardirq_offset: the offset to subtract from hardirq_count() + * @cputime: the cpu time spent in kernel space since the last update + */ +void account_system_time(struct task_struct *p, int hardirq_offset, + cputime_t cputime) +{ + struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat; + runqueue_t *rq = this_rq(); + cputime64_t tmp; + + p->stime = cputime_add(p->stime, cputime); + + /* Check for signals (SIGPROF, SIGXCPU & SIGKILL). */ + if (likely(p->signal && p->exit_state < EXIT_ZOMBIE)) { + check_rlimit(p, cputime); + account_it_prof(p, cputime); + } + + /* Add system time to cpustat. */ + tmp = cputime_to_cputime64(cputime); + if (hardirq_count() - hardirq_offset) + cpustat->irq = cputime64_add(cpustat->irq, tmp); + else if (softirq_count()) + cpustat->softirq = cputime64_add(cpustat->softirq, tmp); + else if (p != rq->idle) + cpustat->system = cputime64_add(cpustat->system, tmp); + else if (atomic_read(&rq->nr_iowait) > 0) + cpustat->iowait = cputime64_add(cpustat->iowait, tmp); + else + cpustat->idle = cputime64_add(cpustat->idle, tmp); +} + +/* + * Account for involuntary wait time. + * @p: the process from which the cpu time has been stolen + * @steal: the cpu time spent in involuntary wait + */ +void account_steal_time(struct task_struct *p, cputime_t steal) +{ + struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat; + cputime64_t steal64 = cputime_to_cputime64(steal); + runqueue_t *rq = this_rq(); + + if (p == rq->idle) + cpustat->system = cputime64_add(cpustat->system, steal64); + else + cpustat->steal = cputime64_add(cpustat->steal, steal64); +} + /* * This function gets called by the timer code, with HZ frequency. * We call it with interrupts disabled. @@ -2257,42 +2399,20 @@ EXPORT_PER_CPU_SYMBOL(kstat); * It also gets called by the fork code, when changing the parent's * timeslices. */ -void scheduler_tick(int user_ticks, int sys_ticks) +void scheduler_tick(void) { int cpu = smp_processor_id(); - struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat; runqueue_t *rq = this_rq(); task_t *p = current; rq->timestamp_last_tick = sched_clock(); - if (rcu_pending(cpu)) - rcu_check_callbacks(cpu, user_ticks); - - /* note: this timer irq context must be accounted for as well */ - if (hardirq_count() - HARDIRQ_OFFSET) { - cpustat->irq += sys_ticks; - sys_ticks = 0; - } else if (softirq_count()) { - cpustat->softirq += sys_ticks; - sys_ticks = 0; - } - if (p == rq->idle) { - if (atomic_read(&rq->nr_iowait) > 0) - cpustat->iowait += sys_ticks; - else - cpustat->idle += sys_ticks; if (wake_priority_sleeper(rq)) goto out; rebalance_tick(cpu, rq, SCHED_IDLE); return; } - if (TASK_NICE(p) > 0) - cpustat->nice += user_ticks; - else - cpustat->user += user_ticks; - cpustat->system += sys_ticks; /* Task might have expired already, but not scheduled off yet */ if (p->array != rq->active) { diff --git a/kernel/signal.c b/kernel/signal.c index d800b3f97323..6d0a3bd948ab 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -375,8 +375,8 @@ void __exit_signal(struct task_struct *tsk) * We won't ever get here for the group leader, since it * will have been the last reference on the signal_struct. */ - sig->utime += tsk->utime; - sig->stime += tsk->stime; + sig->utime = cputime_add(sig->utime, tsk->utime); + sig->stime = cputime_add(sig->stime, tsk->stime); sig->min_flt += tsk->min_flt; sig->maj_flt += tsk->maj_flt; sig->nvcsw += tsk->nvcsw; @@ -1470,8 +1470,10 @@ void do_notify_parent(struct task_struct *tsk, int sig) info.si_uid = tsk->uid; /* FIXME: find out whether or not this is supposed to be c*time. */ - info.si_utime = tsk->utime + tsk->signal->utime; - info.si_stime = tsk->stime + tsk->signal->stime; + info.si_utime = cputime_to_jiffies(cputime_add(tsk->utime, + tsk->signal->utime)); + info.si_stime = cputime_to_jiffies(cputime_add(tsk->stime, + tsk->signal->stime)); info.si_status = tsk->exit_code & 0x7f; if (tsk->exit_code & 0x80) @@ -1527,8 +1529,8 @@ do_notify_parent_cldstop(struct task_struct *tsk, struct task_struct *parent, info.si_uid = tsk->uid; /* FIXME: find out whether or not this is supposed to be c*time. */ - info.si_utime = tsk->utime; - info.si_stime = tsk->stime; + info.si_utime = cputime_to_jiffies(tsk->utime); + info.si_stime = cputime_to_jiffies(tsk->stime); info.si_code = why; switch (why) { diff --git a/kernel/sys.c b/kernel/sys.c index 20080da0c3de..6e354fd380e7 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -893,15 +893,15 @@ asmlinkage long sys_times(struct tms __user * tbuf) struct tms tmp; struct task_struct *tsk = current; struct task_struct *t; - unsigned long utime, stime, cutime, cstime; + cputime_t utime, stime, cutime, cstime; read_lock(&tasklist_lock); utime = tsk->signal->utime; stime = tsk->signal->stime; t = tsk; do { - utime += t->utime; - stime += t->stime; + utime = cputime_add(utime, t->utime); + stime = cputime_add(stime, t->stime); t = next_thread(t); } while (t != tsk); @@ -920,10 +920,10 @@ asmlinkage long sys_times(struct tms __user * tbuf) spin_unlock_irq(&tsk->sighand->siglock); read_unlock(&tasklist_lock); - tmp.tms_utime = jiffies_to_clock_t(utime); - tmp.tms_stime = jiffies_to_clock_t(stime); - tmp.tms_cutime = jiffies_to_clock_t(cutime); - tmp.tms_cstime = jiffies_to_clock_t(cstime); + tmp.tms_utime = cputime_to_clock_t(utime); + tmp.tms_stime = cputime_to_clock_t(stime); + tmp.tms_cutime = cputime_to_clock_t(cutime); + tmp.tms_cstime = cputime_to_clock_t(cstime); if (copy_to_user(tbuf, &tmp, sizeof(struct tms))) return -EFAULT; } @@ -1528,7 +1528,7 @@ void k_getrusage(struct task_struct *p, int who, struct rusage *r) { struct task_struct *t; unsigned long flags; - unsigned long utime, stime; + cputime_t utime, stime; memset((char *) r, 0, sizeof *r); @@ -1545,12 +1545,12 @@ void k_getrusage(struct task_struct *p, int who, struct rusage *r) r->ru_minflt = p->signal->cmin_flt; r->ru_majflt = p->signal->cmaj_flt; spin_unlock_irqrestore(&p->sighand->siglock, flags); - jiffies_to_timeval(utime, &r->ru_utime); - jiffies_to_timeval(stime, &r->ru_stime); + cputime_to_timeval(utime, &r->ru_utime); + cputime_to_timeval(stime, &r->ru_stime); break; case RUSAGE_SELF: spin_lock_irqsave(&p->sighand->siglock, flags); - utime = stime = 0; + utime = stime = cputime_zero; goto sum_group; case RUSAGE_BOTH: spin_lock_irqsave(&p->sighand->siglock, flags); @@ -1561,16 +1561,16 @@ void k_getrusage(struct task_struct *p, int who, struct rusage *r) r->ru_minflt = p->signal->cmin_flt; r->ru_majflt = p->signal->cmaj_flt; sum_group: - utime += p->signal->utime; - stime += p->signal->stime; + utime = cputime_add(utime, p->signal->utime); + stime = cputime_add(stime, p->signal->stime); r->ru_nvcsw += p->signal->nvcsw; r->ru_nivcsw += p->signal->nivcsw; r->ru_minflt += p->signal->min_flt; r->ru_majflt += p->signal->maj_flt; t = p; do { - utime += t->utime; - stime += t->stime; + utime = cputime_add(utime, t->utime); + stime = cputime_add(stime, t->stime); r->ru_nvcsw += t->nvcsw; r->ru_nivcsw += t->nivcsw; r->ru_minflt += t->min_flt; @@ -1578,8 +1578,8 @@ void k_getrusage(struct task_struct *p, int who, struct rusage *r) t = next_thread(t); } while (t != p); spin_unlock_irqrestore(&p->sighand->siglock, flags); - jiffies_to_timeval(utime, &r->ru_utime); - jiffies_to_timeval(stime, &r->ru_stime); + cputime_to_timeval(utime, &r->ru_utime); + cputime_to_timeval(stime, &r->ru_stime); break; default: BUG(); diff --git a/kernel/timer.c b/kernel/timer.c index ec35a6e801a8..6bb47b0e4983 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -806,59 +806,6 @@ static void update_wall_time(unsigned long ticks) } while (ticks); } -static inline void do_process_times(struct task_struct *p, - unsigned long user, unsigned long system) -{ - unsigned long psecs; - - psecs = (p->utime += user); - psecs += (p->stime += system); - if (p->signal && !unlikely(p->exit_state) && - psecs / HZ >= p->signal->rlim[RLIMIT_CPU].rlim_cur) { - /* Send SIGXCPU every second.. */ - if (!(psecs % HZ)) - send_sig(SIGXCPU, p, 1); - /* and SIGKILL when we go over max.. */ - if (psecs / HZ >= p->signal->rlim[RLIMIT_CPU].rlim_max) - send_sig(SIGKILL, p, 1); - } -} - -static inline void do_it_virt(struct task_struct * p, unsigned long ticks) -{ - unsigned long it_virt = p->it_virt_value; - - if (it_virt) { - it_virt -= ticks; - if (!it_virt) { - it_virt = p->it_virt_incr; - send_sig(SIGVTALRM, p, 1); - } - p->it_virt_value = it_virt; - } -} - -static inline void do_it_prof(struct task_struct *p) -{ - unsigned long it_prof = p->it_prof_value; - - if (it_prof) { - if (--it_prof == 0) { - it_prof = p->it_prof_incr; - send_sig(SIGPROF, p, 1); - } - p->it_prof_value = it_prof; - } -} - -static void update_one_process(struct task_struct *p, unsigned long user, - unsigned long system, int cpu) -{ - do_process_times(p, user, system); - do_it_virt(p, user); - do_it_prof(p); -} - /* * Called from the timer interrupt handler to charge one tick to the current * process. user_tick is 1 if the tick is user time, 0 for system. @@ -866,11 +813,17 @@ static void update_one_process(struct task_struct *p, unsigned long user, void update_process_times(int user_tick) { struct task_struct *p = current; - int cpu = smp_processor_id(), system = user_tick ^ 1; + int cpu = smp_processor_id(); - update_one_process(p, user_tick, system, cpu); + /* Note: this timer irq context must be accounted for as well. */ + if (user_tick) + account_user_time(p, jiffies_to_cputime(1)); + else + account_system_time(p, HARDIRQ_OFFSET, jiffies_to_cputime(1)); run_local_timers(); - scheduler_tick(user_tick, system); + if (rcu_pending(cpu)) + rcu_check_callbacks(cpu, user_tick); + scheduler_tick(); } /* diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 967958c7fae1..7f2951f4ddca 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -61,7 +61,8 @@ static unsigned long badness(struct task_struct *p, unsigned long uptime) * of seconds. There is no particular reason for this other than * that it turned out to work very well in practice. */ - cpu_time = (p->utime + p->stime) >> (SHIFT_HZ + 3); + cpu_time = (cputime_to_jiffies(p->utime) + cputime_to_jiffies(p->stime)) + >> (SHIFT_HZ + 3); if (uptime >= p->start_time.tv_sec) run_time = (uptime - p->start_time.tv_sec) >> 10; -- cgit v1.2.3 From a6ab0c16edd9bf13db04afc7cd88cb137fe770aa Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 11 Jan 2005 01:40:53 -0800 Subject: [PATCH] cputime: microsecond based cputime for s390 This patch adds the architecture magic to replace the jiffies based cputime with microsecond based cputime and it adds code to calculate involuntary wait time. With this patch the numbers reported by top and ps when running on LPAR or z/VM are finally not junk anymore. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/s390/Kconfig | 7 ++ arch/s390/kernel/binfmt_elf32.c | 5 +- arch/s390/kernel/entry.S | 135 +++++++++++++++++++++++++++++-- arch/s390/kernel/entry64.S | 128 ++++++++++++++++++++++++++++-- arch/s390/kernel/irq.c | 8 ++ arch/s390/kernel/time.c | 42 +++------- arch/s390/kernel/vtime.c | 111 ++++++++++++++++++++++---- include/asm-s390/cputime.h | 170 +++++++++++++++++++++++++++++++++++++++- include/asm-s390/hardirq.h | 1 + include/asm-s390/lowcore.h | 47 +++++++++-- include/asm-s390/system.h | 18 +++++ include/asm-s390/timer.h | 2 - include/linux/hardirq.h | 18 ++++- kernel/softirq.c | 1 + 14 files changed, 620 insertions(+), 73 deletions(-) (limited to 'include/linux') diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 85ecab32be89..8394c4e51073 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -367,6 +367,13 @@ config VIRT_TIMER This provides a kernel interface for virtual CPU timers. Default is disabled. +config VIRT_CPU_ACCOUNTING + bool "Base user process accounting on virtual cpu timer" + depends on VIRT_TIMER + help + Select this option to use CPU timer deltas to do user + process accounting. + config APPLDATA_BASE bool "Linux - VM Monitor Stream, base infrastructure" depends on PROC_FS && VIRT_TIMER=y diff --git a/arch/s390/kernel/binfmt_elf32.c b/arch/s390/kernel/binfmt_elf32.c index ed234bf06d1c..03ba5893f17b 100644 --- a/arch/s390/kernel/binfmt_elf32.c +++ b/arch/s390/kernel/binfmt_elf32.c @@ -202,9 +202,8 @@ MODULE_AUTHOR("Gerhard Tonn "); static __inline__ void cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) { - unsigned long jiffies = cputime_to_jiffies(cputime); - value->tv_usec = (jiffies % HZ) * (1000000L / HZ); - value->tv_sec = jiffies / HZ; + value->tv_usec = cputime % 1000000; + value->tv_sec = cputime / 1000000; } #include "../../../fs/binfmt_elf.c" diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index f72f9ec9be55..c0e09b33febe 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -66,6 +66,27 @@ STACK_SIZE = 1 << STACK_SHIFT * R15 - kernel stack pointer */ + .macro STORE_TIMER lc_offset +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + stpt \lc_offset +#endif + .endm + +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + .macro UPDATE_VTIME lc_from,lc_to,lc_sum + lm %r10,%r11,\lc_from + sl %r10,\lc_to + sl %r11,\lc_to+4 + bc 3,BASED(0f) + sl %r10,BASED(.Lc_1) +0: al %r10,\lc_sum + al %r11,\lc_sum+4 + bc 12,BASED(1f) + al %r10,BASED(.Lc_1) +1: stm %r10,%r11,\lc_sum + .endm +#endif + .macro SAVE_ALL_BASE savearea stm %r12,%r15,\savearea l %r13,__LC_SVC_NEW_PSW+4 # load &system_call to %r13 @@ -118,6 +139,7 @@ STACK_SIZE = 1 << STACK_SHIFT ni __LC_RETURN_PSW+1,0xfd # clear wait state bit .endif lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user + STORE_TIMER __LC_EXIT_TIMER lpsw __LC_RETURN_PSW # back to caller .endm @@ -159,9 +181,21 @@ __critical_start: .globl system_call system_call: + STORE_TIMER __LC_SYNC_ENTER_TIMER +sysc_saveall: SAVE_ALL_BASE __LC_SAVE_AREA SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 lh %r7,0x8a # get svc number from lowcore +#ifdef CONFIG_VIRT_CPU_ACCOUNTING +sysc_vtime: + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + bz BASED(sysc_do_svc) + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER +sysc_stime: + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER +sysc_update: + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +#endif sysc_do_svc: l %r9,__LC_THREAD_INFO # load pointer to thread_info struct sla %r7,2 # *4 and test for svc 0 @@ -391,10 +425,19 @@ pgm_check_handler: * we just ignore the PER event (FIXME: is there anything we have to do * for LPSW?). */ + STORE_TIMER __LC_SYNC_ENTER_TIMER SAVE_ALL_BASE __LC_SAVE_AREA tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception bnz BASED(pgm_per) # got per exception -> special case SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + bz BASED(pgm_no_vtime) + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +pgm_no_vtime: +#endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct l %r3,__LC_PGM_ILC # load program interruption code la %r8,0x7f @@ -425,6 +468,14 @@ pgm_per: # pgm_per_std: SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + bz BASED(pgm_no_vtime2) + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +pgm_no_vtime2: +#endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct l %r1,__TI_task(%r9) mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID @@ -442,6 +493,14 @@ pgm_per_std: # pgm_svcper: SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + bz BASED(pgm_no_vtime3) + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +pgm_no_vtime3: +#endif lh %r7,0x8a # get svc number from lowcore l %r9,__LC_THREAD_INFO # load pointer to thread_info struct l %r1,__TI_task(%r9) @@ -458,9 +517,18 @@ pgm_svcper: .globl io_int_handler io_int_handler: + STORE_TIMER __LC_ASYNC_ENTER_TIMER stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+16 SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+16,0 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + bz BASED(io_no_vtime) + UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER +io_no_vtime: +#endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ la %r2,SP_PTREGS(%r15) # address of register-save area @@ -549,9 +617,18 @@ io_sigpending: .globl ext_int_handler ext_int_handler: + STORE_TIMER __LC_ASYNC_ENTER_TIMER stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+16 SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16,0 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + bz BASED(ext_no_vtime) + UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER +ext_no_vtime: +#endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct la %r2,SP_PTREGS(%r15) # address of register-save area lh %r3,__LC_EXT_INT_CODE # get interruption code @@ -565,8 +642,17 @@ ext_int_handler: .globl mcck_int_handler mcck_int_handler: + STORE_TIMER __LC_ASYNC_ENTER_TIMER SAVE_ALL_BASE __LC_SAVE_AREA+32 SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32,0 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + bz BASED(mcck_no_vtime) + UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER +mcck_no_vtime: +#endif l %r1,BASED(.Ls390_mcck) basr %r14,%r1 # call machine check handler mcck_return: @@ -661,17 +747,47 @@ cleanup_critical: br %r14 cleanup_system_call: - mvc __LC_RETURN_PSW(4),0(%r12) - clc 4(4,%r12),BASED(cleanup_table_system_call) - bne BASED(0f) + mvc __LC_RETURN_PSW(8),0(%r12) +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+4) + bh BASED(0f) + mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER +0: clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+8) + bhe BASED(cleanup_vtime) +#endif + clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn) + bh BASED(0f) mvc __LC_SAVE_AREA(16),__LC_SAVE_AREA+16 0: st %r13,__LC_SAVE_AREA+20 SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 st %r15,__LC_SAVE_AREA+28 lh %r7,0x8a +#ifdef CONFIG_VIRT_CPU_ACCOUNTING +cleanup_vtime: + clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+12) + bhe BASED(cleanup_stime) + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + bz BASED(cleanup_novtime) + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER +cleanup_stime: + clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+16) + bh BASED(cleanup_update) + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER +cleanup_update: + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +cleanup_novtime: +#endif mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_system_call+4) la %r12,__LC_RETURN_PSW br %r14 +cleanup_system_call_insn: + .long sysc_saveall + 0x80000000 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + .long system_call + 0x80000000 + .long sysc_vtime + 0x80000000 + .long sysc_stime + 0x80000000 + .long sysc_update + 0x80000000 +#endif cleanup_sysc_return: mvc __LC_RETURN_PSW(4),0(%r12) @@ -680,15 +796,23 @@ cleanup_sysc_return: br %r14 cleanup_sysc_leave: - clc 4(4,%r12),BASED(cleanup_sysc_leave_lpsw) + clc 4(4,%r12),BASED(cleanup_sysc_leave_insn) + be BASED(0f) +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER + clc 4(4,%r12),BASED(cleanup_sysc_leave_insn+4) be BASED(0f) +#endif mvc __LC_RETURN_PSW(8),SP_PSW(%r15) mvc __LC_SAVE_AREA+16(16),SP_R12(%r15) lm %r0,%r11,SP_R0(%r15) l %r15,SP_R15(%r15) 0: la %r12,__LC_RETURN_PSW br %r14 -cleanup_sysc_leave_lpsw: +cleanup_sysc_leave_insn: +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + .long sysc_leave + 14 + 0x80000000 +#endif .long sysc_leave + 10 + 0x80000000 /* @@ -704,6 +828,7 @@ cleanup_sysc_leave_lpsw: .L0x028: .short 0x028 .L0x030: .short 0x030 .L0x038: .short 0x038 +.Lc_1: .long 1 /* * Symbol constants diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index adbe2a5f5f72..51527ab8c8f9 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -58,6 +58,21 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) #define BASED(name) name-system_call(%r13) + .macro STORE_TIMER lc_offset +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + stpt \lc_offset +#endif + .endm + +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + .macro UPDATE_VTIME lc_from,lc_to,lc_sum + lg %r10,\lc_from + slg %r10,\lc_to + alg %r10,\lc_sum + stg %r10,\lc_sum + .endm +#endif + /* * Register usage in interrupt handlers: * R9 - pointer to current task structure @@ -117,6 +132,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) ni __LC_RETURN_PSW+1,0xfd # clear wait state bit .endif lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user + STORE_TIMER __LC_EXIT_TIMER lpswe __LC_RETURN_PSW # back to caller .endm @@ -156,9 +172,21 @@ __critical_start: .globl system_call system_call: + STORE_TIMER __LC_SYNC_ENTER_TIMER +sysc_saveall: SAVE_ALL_BASE __LC_SAVE_AREA SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore +#ifdef CONFIG_VIRT_CPU_ACCOUNTING +sysc_vtime: + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + jz sysc_do_svc + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER +sysc_stime: + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER +sysc_update: + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +#endif sysc_do_svc: lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct slag %r7,%r7,2 # *4 and test for svc 0 @@ -441,10 +469,19 @@ pgm_check_handler: * we just ignore the PER event (FIXME: is there anything we have to do * for LPSW?). */ + STORE_TIMER __LC_SYNC_ENTER_TIMER SAVE_ALL_BASE __LC_SAVE_AREA tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception jnz pgm_per # got per exception -> special case SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + jz pgm_no_vtime + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +pgm_no_vtime: +#endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lgf %r3,__LC_PGM_ILC # load program interruption code lghi %r8,0x7f @@ -475,6 +512,14 @@ pgm_per: # pgm_per_std: SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + jz pgm_no_vtime2 + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +pgm_no_vtime2: +#endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lg %r1,__TI_task(%r9) mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID @@ -492,6 +537,14 @@ pgm_per_std: # pgm_svcper: SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + jz pgm_no_vtime3 + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +pgm_no_vtime3: +#endif llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lg %r1,__TI_task(%r9) @@ -507,9 +560,18 @@ pgm_svcper: */ .globl io_int_handler io_int_handler: + STORE_TIMER __LC_ASYNC_ENTER_TIMER stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+32 SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+32,0 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + jz io_no_vtime + UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER +io_no_vtime: +#endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct la %r2,SP_PTREGS(%r15) # address of register-save area brasl %r14,do_IRQ # call standard irq handler @@ -595,9 +657,18 @@ io_sigpending: */ .globl ext_int_handler ext_int_handler: + STORE_TIMER __LC_ASYNC_ENTER_TIMER stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+32 SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32,0 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + jz ext_no_vtime + UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER +ext_no_vtime: +#endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct la %r2,SP_PTREGS(%r15) # address of register-save area llgh %r3,__LC_EXT_INT_CODE # get interruption code @@ -609,8 +680,17 @@ ext_int_handler: */ .globl mcck_int_handler mcck_int_handler: + STORE_TIMER __LC_ASYNC_ENTER_TIMER SAVE_ALL_BASE __LC_SAVE_AREA+64 SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64,0 +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + jz mcck_no_vtime + UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER +mcck_no_vtime: +#endif brasl %r14,s390_do_machine_check mcck_return: RESTORE_ALL 0 @@ -700,17 +780,47 @@ cleanup_critical: br %r14 cleanup_system_call: - mvc __LC_RETURN_PSW(8),0(%r12) - clc 8(8,%r12),BASED(cleanup_table_system_call) - jne 0f + mvc __LC_RETURN_PSW(16),0(%r12) +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+8) + jh 0f + mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER +0: clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+16) + jhe cleanup_vtime +#endif + clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn) + jh 0f mvc __LC_SAVE_AREA(32),__LC_SAVE_AREA+32 0: stg %r13,__LC_SAVE_AREA+40 SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 stg %r15,__LC_SAVE_AREA+56 llgh %r7,__LC_SVC_INT_CODE +#ifdef CONFIG_VIRT_CPU_ACCOUNTING +cleanup_vtime: + clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24) + jhe cleanup_stime + tm SP_PSW+1(%r15),0x01 # interrupting from user ? + jz cleanup_novtime + UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER +cleanup_stime: + clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+32) + jh cleanup_update + UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER +cleanup_update: + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER +cleanup_novtime: +#endif mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_system_call+8) la %r12,__LC_RETURN_PSW br %r14 +cleanup_system_call_insn: + .quad sysc_saveall +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + .quad system_call + .quad sysc_vtime + .quad sysc_stime + .quad sysc_update +#endif cleanup_sysc_return: mvc __LC_RETURN_PSW(8),0(%r12) @@ -719,15 +829,23 @@ cleanup_sysc_return: br %r14 cleanup_sysc_leave: - clc 8(8,%r12),BASED(cleanup_sysc_leave_lpsw) + clc 8(8,%r12),BASED(cleanup_sysc_leave_insn) + je 0f +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER + clc 8(8,%r12),BASED(cleanup_sysc_leave_insn+8) je 0f +#endif mvc __LC_RETURN_PSW(16),SP_PSW(%r15) mvc __LC_SAVE_AREA+32(32),SP_R12(%r15) lmg %r0,%r11,SP_R0(%r15) lg %r15,SP_R15(%r15) 0: la %r12,__LC_RETURN_PSW br %r14 -cleanup_sysc_leave_lpsw: +cleanup_sysc_leave_insn: +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + .quad sysc_leave + 16 +#endif .quad sysc_leave + 12 /* diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 75275fe905b1..59bfceabaebe 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -71,6 +71,10 @@ asmlinkage void do_softirq(void) local_irq_save(flags); + account_system_vtime(current); + + local_bh_disable(); + if (local_softirq_pending()) { /* Get current stack pointer. */ asm volatile("la %0,0(15)" : "=a" (old)); @@ -93,6 +97,10 @@ asmlinkage void do_softirq(void) __do_softirq(); } + account_system_vtime(current); + + __local_bh_enable(); + local_irq_restore(flags); } diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 2fea300f4b47..995e2cd38e77 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -150,28 +150,6 @@ int do_settimeofday(struct timespec *tv) EXPORT_SYMBOL(do_settimeofday); -#ifndef CONFIG_ARCH_S390X - -static inline __u32 -__calculate_ticks(__u64 elapsed) -{ - register_pair rp; - - rp.pair = elapsed >> 1; - asm ("dr %0,%1" : "+d" (rp) : "d" (CLK_TICKS_PER_JIFFY >> 1)); - return rp.subreg.odd; -} - -#else /* CONFIG_ARCH_S390X */ - -static inline __u32 -__calculate_ticks(__u64 elapsed) -{ - return elapsed / CLK_TICKS_PER_JIFFY; -} - -#endif /* CONFIG_ARCH_S390X */ - #ifdef CONFIG_PROFILING #define s390_do_profile(regs) profile_tick(CPU_PROFILING, regs) @@ -187,14 +165,14 @@ __calculate_ticks(__u64 elapsed) void account_ticks(struct pt_regs *regs) { __u64 tmp; - __u32 ticks; + __u32 ticks, xticks; /* Calculate how many ticks have passed. */ if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) return; tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer; if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than two ticks ? */ - ticks = __calculate_ticks(tmp) + 1; + ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1; S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY * (__u64) ticks; } else if (tmp >= CLK_TICKS_PER_JIFFY) { @@ -216,11 +194,9 @@ void account_ticks(struct pt_regs *regs) */ write_seqlock(&xtime_lock); if (S390_lowcore.jiffy_timer > xtime_cc) { - __u32 xticks; - tmp = S390_lowcore.jiffy_timer - xtime_cc; if (tmp >= 2*CLK_TICKS_PER_JIFFY) { - xticks = __calculate_ticks(tmp); + xticks = __div(tmp, CLK_TICKS_PER_JIFFY); xtime_cc += (__u64) xticks * CLK_TICKS_PER_JIFFY; } else { xticks = 1; @@ -230,14 +206,18 @@ void account_ticks(struct pt_regs *regs) do_timer(regs); } write_sequnlock(&xtime_lock); - while (ticks--) - update_process_times(user_mode(regs)); #else - while (ticks--) { + for (xticks = ticks; xticks > 0; xticks--) do_timer(regs); +#endif + +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + account_user_vtime(current); +#else + while (ticks--) update_process_times(user_mode(regs)); - } #endif + s390_do_profile(regs); } diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 02d2179e4082..63cdfec3ba99 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -25,7 +27,95 @@ static ext_int_info_t ext_int_info_timer; DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); -void start_cpu_timer(void) +#ifdef CONFIG_VIRT_CPU_ACCOUNTING +/* + * Update process times based on virtual cpu times stored by entry.S + * to the lowcore fields user_timer, system_timer & steal_clock. + */ +void account_user_vtime(struct task_struct *tsk) +{ + cputime_t cputime; + __u64 timer, clock; + int rcu_user_flag; + + timer = S390_lowcore.last_update_timer; + clock = S390_lowcore.last_update_clock; + asm volatile (" STPT %0\n" /* Store current cpu timer value */ + " STCK %1" /* Store current tod clock value */ + : "=m" (S390_lowcore.last_update_timer), + "=m" (S390_lowcore.last_update_clock) ); + S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer; + S390_lowcore.steal_clock += S390_lowcore.last_update_clock - clock; + + cputime = S390_lowcore.user_timer >> 12; + rcu_user_flag = cputime != 0; + S390_lowcore.user_timer -= cputime << 12; + S390_lowcore.steal_clock -= cputime << 12; + account_user_time(tsk, cputime); + + cputime = S390_lowcore.system_timer >> 12; + S390_lowcore.system_timer -= cputime << 12; + S390_lowcore.steal_clock -= cputime << 12; + account_system_time(tsk, HARDIRQ_OFFSET, cputime); + + cputime = S390_lowcore.steal_clock; + if ((__s64) cputime > 0) { + cputime >>= 12; + S390_lowcore.steal_clock -= cputime << 12; + account_steal_time(tsk, cputime); + } + + run_local_timers(); + if (rcu_pending(smp_processor_id())) + rcu_check_callbacks(smp_processor_id(), rcu_user_flag); + scheduler_tick(); +} + +/* + * Update process times based on virtual cpu times stored by entry.S + * to the lowcore fields user_timer, system_timer & steal_clock. + */ +void account_system_vtime(struct task_struct *tsk) +{ + cputime_t cputime; + __u64 timer; + + timer = S390_lowcore.last_update_timer; + asm volatile (" STPT %0" /* Store current cpu timer value */ + : "=m" (S390_lowcore.last_update_timer) ); + S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer; + + cputime = S390_lowcore.system_timer >> 12; + S390_lowcore.system_timer -= cputime << 12; + S390_lowcore.steal_clock -= cputime << 12; + account_system_time(tsk, 0, cputime); +} + +static inline void set_vtimer(__u64 expires) +{ + __u64 timer; + + asm volatile (" STPT %0\n" /* Store current cpu timer value */ + " SPT %1" /* Set new value immediatly afterwards */ + : "=m" (timer) : "m" (expires) ); + S390_lowcore.system_timer += S390_lowcore.last_update_timer - timer; + S390_lowcore.last_update_timer = expires; + + /* store expire time for this CPU timer */ + per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires; +} +#else +static inline void set_vtimer(__u64 expires) +{ + S390_lowcore.last_update_timer = expires; + asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer)); + + /* store expire time for this CPU timer */ + per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires; +} +#endif + +static void start_cpu_timer(void) { struct vtimer_queue *vt_list; @@ -33,7 +123,7 @@ void start_cpu_timer(void) set_vtimer(vt_list->idle); } -void stop_cpu_timer(void) +static void stop_cpu_timer(void) { __u64 done; struct vtimer_queue *vt_list; @@ -71,19 +161,11 @@ void stop_cpu_timer(void) set_vtimer(VTIMER_MAX_SLICE); } -void set_vtimer(__u64 expires) -{ - asm volatile ("SPT %0" : : "m" (expires)); - - /* store expire time for this CPU timer */ - per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires; -} - /* * Sorted add to a list. List is linear searched until first bigger * element is found. */ -void list_add_sorted(struct vtimer_list *timer, struct list_head *head) +static void list_add_sorted(struct vtimer_list *timer, struct list_head *head) { struct vtimer_list *event; @@ -429,11 +511,12 @@ void init_cpu_vtimer(void) { struct vtimer_queue *vt_list; unsigned long cr0; - __u64 timer; /* kick the virtual timer */ - timer = VTIMER_MAX_SLICE; - asm volatile ("SPT %0" : : "m" (timer)); + S390_lowcore.exit_timer = VTIMER_MAX_SLICE; + S390_lowcore.last_update_timer = VTIMER_MAX_SLICE; + asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer)); + asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock)); __ctl_store(cr0, 0, 0); cr0 |= 0x400; __ctl_load(cr0, 0, 0); diff --git a/include/asm-s390/cputime.h b/include/asm-s390/cputime.h index ad989e5d369c..216d861337e6 100644 --- a/include/asm-s390/cputime.h +++ b/include/asm-s390/cputime.h @@ -1,6 +1,168 @@ -#ifndef __S390_CPUTIME_H -#define __S390_CPUTIME_H +/* + * include/asm-s390/cputime.h + * + * (C) Copyright IBM Corp. 2004 + * + * Author: Martin Schwidefsky + */ -#include +#ifndef _S390_CPUTIME_H +#define _S390_CPUTIME_H -#endif /* __S390_CPUTIME_H */ +/* We want to use micro-second resolution. */ + +typedef unsigned long long cputime_t; +typedef unsigned long long cputime64_t; + +#ifndef __s390x__ + +static inline unsigned int +__div(unsigned long long n, unsigned int base) +{ + register_pair rp; + + rp.pair = n >> 1; + asm ("dr %0,%1" : "+d" (rp) : "d" (base >> 1)); + return rp.subreg.odd; +} + +#else /* __s390x__ */ + +static inline unsigned int +__div(unsigned long long n, unsigned int base) +{ + return n / base; +} + +#endif /* __s390x__ */ + +#define cputime_zero (0ULL) +#define cputime_max ((~0UL >> 1) - 1) +#define cputime_add(__a, __b) ((__a) + (__b)) +#define cputime_sub(__a, __b) ((__a) - (__b)) +#define cputime_eq(__a, __b) ((__a) == (__b)) +#define cputime_gt(__a, __b) ((__a) > (__b)) +#define cputime_ge(__a, __b) ((__a) >= (__b)) +#define cputime_lt(__a, __b) ((__a) < (__b)) +#define cputime_le(__a, __b) ((__a) <= (__b)) +#define cputime_to_jiffies(__ct) (__div((__ct), 1000000 / HZ)) +#define jiffies_to_cputime(__hz) ((cputime_t)(__hz) * (1000000 / HZ)) + +#define cputime64_zero (0ULL) +#define cputime64_add(__a, __b) ((__a) + (__b)) +#define cputime_to_cputime64(__ct) (__ct) + +static inline u64 +cputime64_to_jiffies64(cputime64_t cputime) +{ + do_div(cputime, 1000000 / HZ); + return cputime; +} + +/* + * Convert cputime to milliseconds and back. + */ +static inline unsigned int +cputime_to_msecs(const cputime_t cputime) +{ + return __div(cputime, 1000); +} + +static inline cputime_t +msecs_to_cputime(const unsigned int m) +{ + return (cputime_t) m * 1000; +} + +/* + * Convert cputime to milliseconds and back. + */ +static inline unsigned int +cputime_to_secs(const cputime_t cputime) +{ + return __div(cputime, 1000000); +} + +static inline cputime_t +secs_to_cputime(const unsigned int s) +{ + return (cputime_t) s * 1000000; +} + +/* + * Convert cputime to timespec and back. + */ +static inline cputime_t +timespec_to_cputime(const struct timespec *value) +{ + return value->tv_nsec / 1000 + (u64) value->tv_sec * 1000000; +} + +static inline void +cputime_to_timespec(const cputime_t cputime, struct timespec *value) +{ +#ifndef __s390x__ + register_pair rp; + + rp.pair = cputime >> 1; + asm ("dr %0,%1" : "+d" (rp) : "d" (1000000 >> 1)); + value->tv_nsec = rp.subreg.even * 1000; + value->tv_sec = rp.subreg.odd; +#else + value->tv_nsec = (cputime % 1000000) * 1000; + value->tv_sec = cputime / 1000000; +#endif +} + +/* + * Convert cputime to timeval and back. + * Since cputime and timeval have the same resolution (microseconds) + * this is easy. + */ +static inline cputime_t +timeval_to_cputime(const struct timeval *value) +{ + return value->tv_usec + (u64) value->tv_sec * 1000000; +} + +static inline void +cputime_to_timeval(const cputime_t cputime, struct timeval *value) +{ +#ifndef __s390x__ + register_pair rp; + + rp.pair = cputime >> 1; + asm ("dr %0,%1" : "+d" (rp) : "d" (1000000 >> 1)); + value->tv_usec = rp.subreg.even; + value->tv_sec = rp.subreg.odd; +#else + value->tv_usec = cputime % 1000000; + value->tv_sec = cputime / 1000000; +#endif +} + +/* + * Convert cputime to clock and back. + */ +static inline clock_t +cputime_to_clock_t(cputime_t cputime) +{ + return __div(cputime, 1000000 / USER_HZ); +} + +static inline cputime_t +clock_t_to_cputime(unsigned long x) +{ + return (cputime_t) x * (1000000 / USER_HZ); +} + +/* + * Convert cputime64 to clock. + */ +static inline clock_t +cputime64_to_clock_t(cputime64_t cputime) +{ + return __div(cputime, 1000000 / USER_HZ); +} + +#endif /* _S390_CPUTIME_H */ diff --git a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h index 1580b7b2b05e..53e59b4760c5 100644 --- a/include/asm-s390/hardirq.h +++ b/include/asm-s390/hardirq.h @@ -16,6 +16,7 @@ #include #include #include +#include #include /* irq_cpustat_t is unused currently, but could be converted diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h index 0aa1c0f1e705..df5172fc589d 100644 --- a/include/asm-s390/lowcore.h +++ b/include/asm-s390/lowcore.h @@ -56,13 +56,18 @@ #define __LC_RETURN_PSW 0x200 -#define __LC_IRB 0x210 - -#define __LC_DIAG44_OPCODE 0x250 - #define __LC_SAVE_AREA 0xC00 #ifndef __s390x__ +#define __LC_IRB 0x208 +#define __LC_SYNC_ENTER_TIMER 0x248 +#define __LC_ASYNC_ENTER_TIMER 0x250 +#define __LC_EXIT_TIMER 0x258 +#define __LC_LAST_UPDATE_TIMER 0x260 +#define __LC_USER_TIMER 0x268 +#define __LC_SYSTEM_TIMER 0x270 +#define __LC_LAST_UPDATE_CLOCK 0x278 +#define __LC_STEAL_CLOCK 0x280 #define __LC_KERNEL_STACK 0xC40 #define __LC_THREAD_INFO 0xC44 #define __LC_ASYNC_STACK 0xC48 @@ -76,6 +81,16 @@ #define __LC_CURRENT 0xC90 #define __LC_INT_CLOCK 0xC98 #else /* __s390x__ */ +#define __LC_IRB 0x210 +#define __LC_SYNC_ENTER_TIMER 0x250 +#define __LC_ASYNC_ENTER_TIMER 0x258 +#define __LC_EXIT_TIMER 0x260 +#define __LC_LAST_UPDATE_TIMER 0x268 +#define __LC_USER_TIMER 0x270 +#define __LC_SYSTEM_TIMER 0x278 +#define __LC_LAST_UPDATE_CLOCK 0x280 +#define __LC_STEAL_CLOCK 0x288 +#define __LC_DIAG44_OPCODE 0x290 #define __LC_KERNEL_STACK 0xD40 #define __LC_THREAD_INFO 0xD48 #define __LC_ASYNC_STACK 0xD50 @@ -87,7 +102,7 @@ #define __LC_IPLDEV 0xDB8 #define __LC_JIFFY_TIMER 0xDC0 #define __LC_CURRENT 0xDD8 -#define __LC_INT_CLOCK 0xDe8 +#define __LC_INT_CLOCK 0xDE8 #endif /* __s390x__ */ #define __LC_PANIC_MAGIC 0xE00 @@ -169,7 +184,15 @@ struct _lowcore psw_t return_psw; /* 0x200 */ __u8 irb[64]; /* 0x208 */ - __u8 pad8[0xc00-0x248]; /* 0x248 */ + __u64 sync_enter_timer; /* 0x248 */ + __u64 async_enter_timer; /* 0x250 */ + __u64 exit_timer; /* 0x258 */ + __u64 last_update_timer; /* 0x260 */ + __u64 user_timer; /* 0x268 */ + __u64 system_timer; /* 0x270 */ + __u64 last_update_clock; /* 0x278 */ + __u64 steal_clock; /* 0x280 */ + __u8 pad8[0xc00-0x288]; /* 0x288 */ /* System info area */ __u32 save_area[16]; /* 0xc00 */ @@ -250,8 +273,16 @@ struct _lowcore psw_t io_new_psw; /* 0x1f0 */ psw_t return_psw; /* 0x200 */ __u8 irb[64]; /* 0x210 */ - __u32 diag44_opcode; /* 0x250 */ - __u8 pad8[0xc00-0x254]; /* 0x254 */ + __u64 sync_enter_timer; /* 0x250 */ + __u64 async_enter_timer; /* 0x258 */ + __u64 exit_timer; /* 0x260 */ + __u64 last_update_timer; /* 0x268 */ + __u64 user_timer; /* 0x270 */ + __u64 system_timer; /* 0x278 */ + __u64 last_update_clock; /* 0x280 */ + __u64 steal_clock; /* 0x288 */ + __u32 diag44_opcode; /* 0x290 */ + __u8 pad8[0xc00-0x294]; /* 0x294 */ /* System info area */ __u64 save_area[16]; /* 0xc00 */ __u8 pad9[0xd40-0xc80]; /* 0xc80 */ diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h index d9f3498136e1..e8596077e057 100644 --- a/include/asm-s390/system.h +++ b/include/asm-s390/system.h @@ -105,11 +105,29 @@ static inline void restore_access_regs(unsigned int *acrs) #define prepare_arch_switch(rq, next) do { } while(0) #define task_running(rq, p) ((rq)->curr == (p)) + +#ifdef CONFIG_VIRT_CPU_ACCOUNTING +extern void account_user_vtime(struct task_struct *); +extern void account_system_vtime(struct task_struct *); + +#define finish_arch_switch(rq, prev) do { \ + set_fs(current->thread.mm_segment); \ + spin_unlock(&(rq)->lock); \ + account_system_vtime(prev); \ + local_irq_enable(); \ +} while (0) + +#else + +#define account_system_vtime(prev) + #define finish_arch_switch(rq, prev) do { \ set_fs(current->thread.mm_segment); \ spin_unlock_irq(&(rq)->lock); \ } while (0) +#endif + #define nop() __asm__ __volatile__ ("nop") #define xchg(ptr,x) \ diff --git a/include/asm-s390/timer.h b/include/asm-s390/timer.h index 454d1ea85c54..ea0788967c51 100644 --- a/include/asm-s390/timer.h +++ b/include/asm-s390/timer.h @@ -37,8 +37,6 @@ struct vtimer_queue { __u64 idle; /* temp var for idle */ }; -void set_vtimer(__u64 expires); - extern void init_virt_timer(struct vtimer_list *timer); extern void add_virt_timer(void *new); extern void add_virt_timer_periodic(void *new); diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index ba0fcb34c8cd..ebc712e91066 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -4,6 +4,7 @@ #include #include #include +#include /* * We put the hardirq and softirq counter into the preemption @@ -84,7 +85,22 @@ extern void synchronize_irq(unsigned int irq); #define nmi_enter() irq_enter() #define nmi_exit() sub_preempt_count(HARDIRQ_OFFSET) -#define irq_enter() add_preempt_count(HARDIRQ_OFFSET) +#ifndef CONFIG_VIRT_CPU_ACCOUNTING +static inline void account_user_vtime(struct task_struct *tsk) +{ +} + +static inline void account_system_vtime(struct task_struct *tsk) +{ +} +#endif + +#define irq_enter() \ + do { \ + account_system_vtime(current); \ + add_preempt_count(HARDIRQ_OFFSET); \ + } while (0) + extern void irq_exit(void); #endif /* LINUX_HARDIRQ_H */ diff --git a/kernel/softirq.c b/kernel/softirq.c index 9e2d204da364..582a1e8091bc 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -163,6 +163,7 @@ EXPORT_SYMBOL(local_bh_enable); */ void irq_exit(void) { + account_system_vtime(current); sub_preempt_count(IRQ_EXIT_OFFSET); if (!in_interrupt() && local_softirq_pending()) invoke_softirq(); -- cgit v1.2.3 From 54465502760ca40444639dcb8114860dda8a5453 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 11 Jan 2005 01:48:53 -0800 Subject: [PATCH] x86_64: Fix ioremap attribute restoration on i386 and x86-64 We need to save the access flags to properly restore the direct mapping on unmap. For that we use some upper bits in vm_flags Also add a comment for that to the header file. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/mm/ioremap.c | 6 +++--- arch/x86_64/mm/ioremap.c | 10 +++++----- include/linux/vmalloc.h | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c index 1aa488b7f999..58ff04eeb9db 100644 --- a/arch/i386/mm/ioremap.c +++ b/arch/i386/mm/ioremap.c @@ -157,7 +157,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l /* * Ok, go for it.. */ - area = get_vm_area(size, VM_IOREMAP); + area = get_vm_area(size, VM_IOREMAP | (flags << 20)); if (!area) return NULL; area->phys_addr = phys_addr; @@ -235,9 +235,9 @@ void iounmap(volatile void __iomem *addr) if (!p) { printk("__iounmap: bad address %p\n", addr); return; - } + } - if (p->flags && p->phys_addr < virt_to_phys(high_memory) - 1) { + if ((p->flags >> 20) && p->phys_addr < virt_to_phys(high_memory) - 1) { change_page_attr(virt_to_page(__va(p->phys_addr)), p->size >> PAGE_SHIFT, PAGE_KERNEL); diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c index 1a166779eeba..12363e69b0c3 100644 --- a/arch/x86_64/mm/ioremap.c +++ b/arch/x86_64/mm/ioremap.c @@ -175,11 +175,11 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l if (phys_addr >= 0xA0000 && last_addr < 0x100000) return (__force void __iomem *)phys_to_virt(phys_addr); +#ifndef CONFIG_DISCONTIGMEM /* * Don't allow anybody to remap normal RAM that we're using.. */ - if (phys_addr < virt_to_phys(high_memory)) { -#ifndef CONFIG_DISCONTIGMEM + if (last_addr < virt_to_phys(high_memory)) { char *t_addr, *t_end; struct page *page; @@ -189,8 +189,8 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++) if(!PageReserved(page)) return NULL; -#endif } +#endif /* * Mappings have to be page-aligned @@ -202,7 +202,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l /* * Ok, go for it.. */ - area = get_vm_area(size, VM_IOREMAP | (flags << 24)); + area = get_vm_area(size, VM_IOREMAP | (flags << 20)); if (!area) return NULL; area->phys_addr = phys_addr; @@ -263,7 +263,7 @@ void iounmap(volatile void __iomem *addr) } *pprev = p->next; unmap_vm_area(p); - if ((p->flags >> 24) && + if ((p->flags >> 20) && p->phys_addr + p->size - 1 < virt_to_phys(high_memory)) { change_page_attr(virt_to_page(__va(p->phys_addr)), p->size >> PAGE_SHIFT, diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 8c68717810c3..9af7ad38c08d 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -8,6 +8,7 @@ #define VM_IOREMAP 0x00000001 /* ioremap() and friends */ #define VM_ALLOC 0x00000002 /* vmalloc() */ #define VM_MAP 0x00000004 /* vmap()ed pages */ +/* bits [20..32] reserved for arch specific ioremap internals */ struct vm_struct { void *addr; -- cgit v1.2.3 From bf36f91f08100b758a4f12811da05b9c1ce09c90 Mon Sep 17 00:00:00 2001 From: Prasanna Meda Date: Tue, 11 Jan 2005 03:18:08 -0800 Subject: [PATCH] easily tweakable comm length This change still keeps the comm length at 16, but allows easier patching for local modifications, and also introduces a macro to use instead of magic 16, where sizeof(comm) is not preferable to use. Not able to use killall, pidof etc. effectively, when long process names are used for scripts. Just changing the command length from 16 to 32 breaks a.out coredump logic. Deamonise and get_task_comm helped in other places in 2.6.10. Signed-off-by: Prasanna Meda Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/sparc64/kernel/binfmt_aout32.c | 2 +- fs/binfmt_aout.c | 2 +- include/linux/sched.h | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c index 64d547853b48..c54d806e13d2 100644 --- a/arch/sparc64/kernel/binfmt_aout32.c +++ b/arch/sparc64/kernel/binfmt_aout32.c @@ -95,7 +95,7 @@ static int aout32_core_dump(long signr, struct pt_regs *regs, struct file *file) set_fs(KERNEL_DS); has_dumped = 1; current->flags |= PF_DUMPCORE; - strncpy(dump.u_comm, current->comm, sizeof(current->comm)); + strncpy(dump.u_comm, current->comm, sizeof(dump.u_comm)); dump.signal = signr; dump_thread(regs, &dump); diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index acdd53848566..8075fdff2364 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -112,7 +112,7 @@ static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file) set_fs(KERNEL_DS); has_dumped = 1; current->flags |= PF_DUMPCORE; - strncpy(dump.u_comm, current->comm, sizeof(current->comm)); + strncpy(dump.u_comm, current->comm, sizeof(dump.u_comm)); #ifndef __sparc__ dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump))); #endif diff --git a/include/linux/sched.h b/include/linux/sched.h index dcc1814f97e8..96f69aaa0534 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -121,6 +121,9 @@ extern unsigned long nr_iowait(void); #define set_current_state(state_value) \ set_mb(current->state, (state_value)) +/* Task command name length */ +#define TASK_COMM_LEN 16 + /* * Scheduling policies */ @@ -612,7 +615,7 @@ struct task_struct { struct key *thread_keyring; /* keyring private to this thread */ #endif unsigned short used_math; - char comm[16]; + char comm[TASK_COMM_LEN]; /* file system info */ int link_count, total_link_count; /* ipc stuff */ -- cgit v1.2.3 From 66d272434a1b009b94bab07bae98dec39e0a9706 Mon Sep 17 00:00:00 2001 From: Hisashi Hifumi Date: Tue, 11 Jan 2005 03:30:37 -0800 Subject: [PATCH] BUG on error handlings in Ext3 under I/O failure condition I found bugs on error handlings in the functions arround the ext3 file system, which cause inadequate completions of synchronous write I/O operations when disk I/O failures occur. Both 2.4 and 2.6 have this problem. I carried out following experiment: 1. Mount a ext3 file system on a SCSI disk with ordered mode. 2. Open a file on the file system with O_SYNC|O_RDWR|O_TRUNC|O_CREAT flag. 3. Write 512 bytes data to the file by calling write() every 5 seconds, and examine return values from the syscall. from write(). 4. Disconnect the SCSI cable, and examine messages from the kernel. After the SCSI cable is disconnected, write() must fail. But the result was different: write() succeeded for a while even though messages of the kernel notified SCSI I/O error. By applying following modifications, the above problem was solved. Signed-off-by: Hisashi Hifumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/buffer.c | 8 +++++--- fs/fs-writeback.c | 15 ++++++++++----- fs/jbd/commit.c | 3 +++ include/linux/fs.h | 2 +- 4 files changed, 19 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/fs/buffer.c b/fs/buffer.c index 7a31850892cb..341ba4c58a18 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -311,10 +311,10 @@ int file_fsync(struct file *filp, struct dentry *dentry, int datasync) { struct inode * inode = dentry->d_inode; struct super_block * sb; - int ret; + int ret, err; /* sync the inode to buffers */ - write_inode_now(inode, 0); + ret = write_inode_now(inode, 0); /* sync the superblock to buffers */ sb = inode->i_sb; @@ -324,7 +324,9 @@ int file_fsync(struct file *filp, struct dentry *dentry, int datasync) unlock_super(sb); /* .. finally sync the buffers to disk */ - ret = sync_blockdev(sb->s_bdev); + err = sync_blockdev(sb->s_bdev); + if (!ret) + ret = err; return ret; } diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 26f234a0da93..6d0e70efd399 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -558,22 +558,24 @@ void sync_inodes(int wait) * dirty. This is primarily needed by knfsd. */ -void write_inode_now(struct inode *inode, int sync) +int write_inode_now(struct inode *inode, int sync) { + int ret; struct writeback_control wbc = { .nr_to_write = LONG_MAX, .sync_mode = WB_SYNC_ALL, }; if (inode->i_mapping->backing_dev_info->memory_backed) - return; + return 0; might_sleep(); spin_lock(&inode_lock); - __writeback_single_inode(inode, &wbc); + ret = __writeback_single_inode(inode, &wbc); spin_unlock(&inode_lock); if (sync) wait_on_inode(inode); + return ret; } EXPORT_SYMBOL(write_inode_now); @@ -642,8 +644,11 @@ int generic_osync_inode(struct inode *inode, struct address_space *mapping, int need_write_inode_now = 1; spin_unlock(&inode_lock); - if (need_write_inode_now) - write_inode_now(inode, 1); + if (need_write_inode_now) { + err2 = write_inode_now(inode, 1); + if (!err) + err = err2; + } else wait_on_inode(inode); diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index c5c9983e3a60..aa5f22435d0c 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -337,6 +337,9 @@ write_out_data: } spin_unlock(&journal->j_list_lock); + if (err) + __journal_abort_hard(journal); + journal_write_revoke_records(journal, commit_transaction); jbd_debug(3, "JBD: commit phase 2\n"); diff --git a/include/linux/fs.h b/include/linux/fs.h index aa7abb112dbc..4d26f55c1299 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1344,7 +1344,7 @@ static inline void invalidate_remote_inode(struct inode *inode) invalidate_inode_pages(inode->i_mapping); } extern int invalidate_inode_pages2(struct address_space *mapping); -extern void write_inode_now(struct inode *, int); +extern int write_inode_now(struct inode *, int); extern int filemap_fdatawrite(struct address_space *); extern int filemap_flush(struct address_space *); extern int filemap_fdatawait(struct address_space *); -- cgit v1.2.3 From 8f13ed2fa0cc179e1462f8d7c81dd4a62b7e0c88 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 11 Jan 2005 15:35:48 -0800 Subject: [PATCH] x86_64: Fix ACPI SRAT NUMA parsing Fix fallout from the recent nodemask_t changes. The node ids assigned in the SRAT parser were off by one. I added a new first_unset_node() function to nodemask.h to allocate IDs sanely. Signed-off-by: Andi Kleen Signed-off-by: Linus Torvalds --- arch/x86_64/mm/srat.c | 17 ++++++++++------- include/linux/nodemask.h | 9 +++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c index 1db7483a0564..aaf329373367 100644 --- a/arch/x86_64/mm/srat.c +++ b/arch/x86_64/mm/srat.c @@ -20,17 +20,20 @@ static struct acpi_table_slit *acpi_slit; -static DECLARE_BITMAP(nodes_parsed, MAX_NUMNODES) __initdata; +static nodemask_t nodes_parsed __initdata; +static nodemask_t nodes_found __initdata; static struct node nodes[MAX_NUMNODES] __initdata; static __u8 pxm2node[256] __initdata = { [0 ... 255] = 0xff }; static __init int setup_node(int pxm) { - if (pxm2node[pxm] == 0xff) { - if (num_online_nodes() >= MAX_NUMNODES) + unsigned node = pxm2node[pxm]; + if (node == 0xff) { + if (nodes_weight(nodes_found) >= MAX_NUMNODES) return -1; - pxm2node[pxm] = num_online_nodes(); - node_set_online(num_online_nodes()); + node = first_unset_node(nodes_found); + node_set(node, nodes_found); + pxm2node[pxm] = node; } return pxm2node[pxm]; } @@ -140,7 +143,7 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) return; } nd = &nodes[node]; - if (!test_and_set_bit(node, &nodes_parsed)) { + if (!node_test_and_set(node, nodes_parsed)) { nd->start = start; nd->end = end; } else { @@ -171,7 +174,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) return -1; } for (i = 0; i < MAX_NUMNODES; i++) { - if (!test_bit(i, &nodes_parsed)) + if (!node_isset(i, nodes_parsed)) continue; cutoff_node(i, start, end); if (nodes[i].start == nodes[i].end) diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h index 4de843d94147..16475a23efa7 100644 --- a/include/linux/nodemask.h +++ b/include/linux/nodemask.h @@ -38,6 +38,8 @@ * * int first_node(mask) Number lowest set bit, or MAX_NUMNODES * int next_node(node, mask) Next node past 'node', or MAX_NUMNODES + * int first_unset_node(mask) First node not set in mask, or + * MAX_NUMNODES. * * nodemask_t nodemask_of_node(node) Return nodemask with bit 'node' set * NODE_MASK_ALL Initializer - all bits set @@ -235,6 +237,13 @@ static inline int __next_node(int n, const nodemask_t *srcp, int nbits) m; \ }) +#define first_unset_node(mask) __first_unset_node(&(mask)) +static inline int __first_unset_node(const nodemask_t *maskp) +{ + return min_t(int,MAX_NUMNODES, + find_first_zero_bit(maskp->bits, MAX_NUMNODES)); +} + #define NODE_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(MAX_NUMNODES) #if MAX_NUMNODES <= BITS_PER_LONG -- cgit v1.2.3 From 80ce63d3a9a3ca3bcd0232caeb3bfb127af5ad35 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 12 Jan 2005 17:00:45 -0800 Subject: [PATCH] possible rq starvation on oom I stumbled across this the other day. The block layer only uses a single memory pool for request allocation, so it's very possible for eg writes to have allocated them all at any point in time. If that is the case and the machine is low on memory, a reader attempting to allocate a request and failing in blk_alloc_request() can get stuck for a long time since no one is there to wake it up. The solution is either to add the extra mempool so both reads and writes have one, or attempt to handle the situation. I chose the latter, to save the extra memory required for the additional mempool with BLKDEV_MIN_RQ statically allocated requests per-queue. If a read allocation fails and we have no readers in flight for this queue, mark us rq-starved so that the next write being freed will wake up the sleeping reader(s). Same situation would happen for writes as well of course, it's just a lot more unlikely. Signed-off-by: Jens Axboe Signed-off-by: Linus Torvalds --- drivers/block/ll_rw_blk.c | 51 +++++++++++++++++++++++++++++++++++++---------- include/linux/blkdev.h | 1 + 2 files changed, 41 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 98db1776ba31..3994af7e555b 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1438,6 +1438,7 @@ static int blk_init_free_list(request_queue_t *q) struct request_list *rl = &q->rq; rl->count[READ] = rl->count[WRITE] = 0; + rl->starved[READ] = rl->starved[WRITE] = 0; init_waitqueue_head(&rl->wait[READ]); init_waitqueue_head(&rl->wait[WRITE]); init_waitqueue_head(&rl->drain); @@ -1618,6 +1619,22 @@ void ioc_set_batching(request_queue_t *q, struct io_context *ioc) ioc->last_waited = jiffies; } +static void __freed_request(request_queue_t *q, int rw) +{ + struct request_list *rl = &q->rq; + + if (rl->count[rw] < queue_congestion_off_threshold(q)) + clear_queue_congested(q, rw); + + if (rl->count[rw] + 1 <= q->nr_requests) { + smp_mb(); + if (waitqueue_active(&rl->wait[rw])) + wake_up(&rl->wait[rw]); + + blk_clear_queue_full(q, rw); + } +} + /* * A request has just been released. Account for it, update the full and * congestion status, wake up any waiters. Called under q->queue_lock. @@ -1627,17 +1644,17 @@ static void freed_request(request_queue_t *q, int rw) struct request_list *rl = &q->rq; rl->count[rw]--; - if (rl->count[rw] < queue_congestion_off_threshold(q)) - clear_queue_congested(q, rw); - if (rl->count[rw]+1 <= q->nr_requests) { + + __freed_request(q, rw); + + if (unlikely(rl->starved[rw ^ 1])) + __freed_request(q, rw ^ 1); + + if (!rl->count[READ] && !rl->count[WRITE]) { smp_mb(); - if (waitqueue_active(&rl->wait[rw])) - wake_up(&rl->wait[rw]); - blk_clear_queue_full(q, rw); + if (unlikely(waitqueue_active(&rl->drain))) + wake_up(&rl->drain); } - if (unlikely(waitqueue_active(&rl->drain)) && - !rl->count[READ] && !rl->count[WRITE]) - wake_up(&rl->drain); } #define blkdev_free_rq(list) list_entry((list)->next, struct request, queuelist) @@ -1669,8 +1686,7 @@ static struct request *get_request(request_queue_t *q, int rw, int gfp_mask) switch (elv_may_queue(q, rw)) { case ELV_MQUEUE_NO: - spin_unlock_irq(q->queue_lock); - goto out; + goto rq_starved; case ELV_MQUEUE_MAY: break; case ELV_MQUEUE_MUST: @@ -1688,6 +1704,7 @@ static struct request *get_request(request_queue_t *q, int rw, int gfp_mask) get_rq: rl->count[rw]++; + rl->starved[rw] = 0; if (rl->count[rw] >= queue_congestion_on_threshold(q)) set_queue_congested(q, rw); spin_unlock_irq(q->queue_lock); @@ -1703,6 +1720,18 @@ get_rq: */ spin_lock_irq(q->queue_lock); freed_request(q, rw); + + /* + * in the very unlikely event that allocation failed and no + * requests for this direction was pending, mark us starved + * so that freeing of a request in the other direction will + * notice us. another possible fix would be to split the + * rq mempool into READ and WRITE + */ +rq_starved: + if (unlikely(rl->count[rw] == 0)) + rl->starved[rw] = 1; + spin_unlock_irq(q->queue_lock); goto out; } diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 1b7dc44bf3c1..5615a3c9e410 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -95,6 +95,7 @@ void swap_io_context(struct io_context **ioc1, struct io_context **ioc2); struct request_list { int count[2]; + int starved[2]; mempool_t *rq_pool; wait_queue_head_t wait[2]; wait_queue_head_t drain; -- cgit v1.2.3